# Custom Theme

This article will tell you how to develop custom theme.

## Extensions based on the default theme

In most cases, you don't want to develop a theme from scratch, but want to extend it based on the default theme. At this time, you can refer to the following methods for theme development.

:::tip
If you want to develop a custom theme from scratch, you can go to [Redevelop a custom theme](/guide/advanced/custom-theme#redevelop-a-custom-theme).
:::

### 1. Basic structure

By default, you need to create a `theme` directory under the project root directory, and then create an `index.ts` or `index.tsx` file under the `theme` directory, which is used to export the theme content.

```bash
├── theme
│   └── index.tsx
```

You can write the `theme/index.tsx` file as follows:

```tsx title="theme/index.tsx"
import Theme from '@modern-js/doc-tools/theme';

const Layout = () => <Theme.Layout beforeNavTitle={<div>some content</div>} />;

export default {
  ...Theme,
  Layout,
};

export * from '@modern-js/doc-tools/theme';
```

On the one hand, you need to export a theme configuration object through `export default`, on the other hand, you need to export all named exported content through `export * from '@modern-js/doc-tools/theme'` so as to ensure your theme works fine.

### 2. Use slot

It is worth noting that the Layout component has designed a series of props to support slot elements. You can use these props to extend the layout of the default theme. For example, change the above Layout component to the following form:

```tsx
import { Layout as DefaultLayout } from '@modern-js/doc-tools/theme';

// Show all props below
const Layout = () => (
  <DefaultLayout
    /* Before home hero */
    beforeHero={<div>beforeHero</div>}
    /* After home hero */
    afterHero={<div>afterHero</div>}
    /* Before home features */
    beforeFeatures={<div>beforeFeatures</div>}
    /* After home features */
    afterFeatures={<div>afterFeatures</div>}
    /* Before doc footer */
    beforeDocFooter={<div>beforeDocFooter</div>}
    /* Doc page front */
    beforeDoc={<div>beforeDoc</div>}
    /* Doc page end */
    afterDoc={<div>afterDoc</div>}
    /* Before the nav bar */
    beforeNav={<div>beforeNav</div>}
    /* Before the title of the nav bar in the upper left corner */
    beforeNavTitle={<span>😄</span>}
    /* After the title of the nav bar in the upper left corner
     */
    afterNavTitle={<div>afterNavTitle</div>}
    /* Above the right outline column */
    beforeOutline={<div>beforeOutline</div>}
    /* Below the outline column on the right */
    afterOutline={<div>afterOutline</div>}
    /* Top of the entire page */
    top={<div>top</div>}
    /* Bottom of the entire page */
    bottom={<div>bottom</div>}
  />
);

export default {
  ...Theme,
  Layout,
};

export * from '@modern-js/doc-tools/theme';
```

### 3. Custom Home page and 404 page

To extend the components of the default theme, in addition to slots, you can also customize the Home page and 404 page, such as:

```tsx title="theme/index.tsx"
import Theme from '@modern-js/doc-tools/theme';

const Layout = () => <Theme.Layout beforeNavTitle={<div>some content</div>} />;

// Custom Home Page
const HomeLayout = () => <div>Home</div>;
// Custom 404 page
const NotFoundLayout = () => <div>404</div>;

export default {
  ...Theme,
  Layout,
  HomeLayout,
  NotFoundLayout,
};

export * from '@modern-js/doc-tools/theme';
```

Of course, you may need to use page data during the development process, you can get it through the Hook [`usePageData`](/api/api-runtime#usepagedata).

## Redevelop a custom theme

If you're developing a custom theme from scratch, you need to understand the basic structure of the theme and the runtime API.

### 1. Basic structure

By default, you need to create a `theme` directory under the project root directory, and then create an `index.ts` or `index.tsx` file under the `theme` directory, which is used to export the theme content.

```bash
├── theme
│   └── index.tsx
```

In the `theme/index.tsx` file, you need to export a Layout component, which is the entry component of your theme:

```ts
// theme/index.tsx
function Layout() {
  return <div>Custom Theme Layout</div>;
}

// The setup function will be called when the page is initialized. It is generally used to monitor global events, and it can be an empty function
const setup = () => {};

// Export Layout component and setup function
// Note: both must export
export { Layout, setup };
```

Layout component will be used to render the layout of the entire document site, you can introduce your custom components in this component, for example:

```ts
// theme/index.tsx
import { Navbar } from './Navbar';

function Layout() {
  return (
    <div>
      <Navbar />
      <div>Custom Theme Layout</div>
    </div>
  );
}

const setup = () => {};

export { Layoutm, setup };

// theme/Navbar.tsx
export function Navbar() {
  return <div>Custom Navbar</div>;
}
```

So the question is, how does the theme component get the page data and the content of the body MDX component? Next, let's take a look at the related APIs.

### 2. Runtime API

#### usePageData

Get information about all data on the site, such as:

```tsx
import { usePageData } from '@modern-js/doc-tools/runtime';

import { usePageData } from '@modern-js/doc-tools/runtime';

function MyComponent() {
  const pageData = usePageData();
  return <div>{pageData.title}</div>;
}
```

#### useLang

Get the current language information, such as:

```tsx
import { useLang } from '@modern-js/doc-tools/runtime';

function MyComponent() {
  const lang = useLang();
  return <div>{lang}</div>;
}
```

#### Content

Get MDX component content, such as:

```tsx
import { Content } from '@modern-js/doc-tools/runtime';

function Layout() {
  return (
    <div>
      <Content />
    </div>
  );
}
```

#### Route Hook

[react-router-dom](https://reactrouter.com/) is used inside the framework to implement routing, so you can directly use the Hook of `react-router-dom`, for example:

```ts
import { useLocation } from '@modern-js/doc-tools/runtime';

function Layout() {
  const location = useLocation();
  return <div>Current location: {location.pathname}</div>;
}
```
