> For AI agents: the complete documentation index is available at https://rspress.rs/llms.txt, the full documentation bundle is available at https://rspress.rs/llms-full.txt.

# Custom theme


For your Agent

If you are using a coding agent, install the [`rspress-custom-theme` Agent Skill](https://github.com/rstackjs/agent-skills#rspress-custom-theme) to help the agent generate a brand-new theme for you.
For more information about AI-assisted development with Rspress, see the [AI page](https://rspress.rs/guide/start/ai.md).

1. For CSS, Rspress provides [CSS variables](#css-variables) and [BEM class names](#bem-classname) for customization.

2. For JS / React, Rspress provides a runtime interface based on ESM re-exports, so you can modify or replace built-in components for your own homepage, sidebar, search components, and more.

   On top of this, there are two modes:

   - [**wrap**](#wrap): **Wrap** and enhance Rspress built-in components with props or slots.
   - [**eject**](#eject): Directly **override** the entire component. You can use the [`rspress eject`](https://rspress.rs/api/commands.md#rspress-eject) command to copy the source code locally and modify it directly.

The following sections introduce these approaches from lighter to deeper customization.

## CSS variables \{#css-variables}

Rspress exposes commonly used CSS variables. Compared with rewriting built-in React components, overriding CSS variables is simpler and easier to maintain. View these CSS variables on the [UI - CSS Variables](https://rspress.rs/ui/vars.md) page, then override them with:

```tree
├── docs
│   └── index.mdx
├── theme
│   ├── index.tsx
│   └── index.css  <-- Copy CSS variable code here to override styles
└── rspress.config.ts
```

```tsx title="theme/index.tsx"
import './index.css';
export * from '@rspress/core/theme-original';
```

Another approach is to use the [globalStyles](https://rspress.rs/api/config/config-basic.md#globalstyles) config in `rspress.config.ts`:

```ts title="rspress.config.ts"
import { defineConfig } from '@rspress/core';
import path from 'path';

export default defineConfig({
  globalStyles: path.join(__dirname, 'styles/index.css'), // Points to your CSS file
});
```

## BEM class names \{#bem-classname}

All built-in Rspress components use the BEM naming convention. You can use these class names to override styles, similar to [CSS Variables](#css-variables).

```css
.rp-[component-name]__[element-name]--[modifier-name] {
  /* styles */
}
```

For example:

```css
.rp-nav {
}
.rp-link {
}
.rp-tabs {
}
.rp-codeblock {
}
.rp-codeblock__title {
}
.rp-codeblock__description {
}
.rp-nav-menu__item,
.rp-nav-menu__item--active {
}
```

## Override built-in components using ESM re-exports \{#reexport}

By default, create a `theme` directory under the project root, then create an `index.ts` or `index.tsx` file inside it to export theme components.

```tree
├── docs
├── theme
│   └── index.tsx
└── rspress.config.ts
```

You can write the `theme/index.tsx` file using built-in components from `@rspress/core/theme-original`:

```tsx title="theme/index.tsx"
import { Layout as BasicLayout } from '@rspress/core/theme-original';

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

export { Layout }; //[!code highlight]
export * from '@rspress/core/theme-original'; //[!code highlight]
```

When you override built-in components with **ESM re-exports**, Rspress internal references to those components use your re-exported version first.

:::note About @rspress/core/theme-original

`@rspress/core/theme-original` avoids circular references. Use it only when customizing themes.

```tree
├── docs
│   └── index.mdx <-- use "@rspress/core/theme"
├── theme
│   └── index.tsx <-- use "@rspress/core/theme-original"
└── rspress.config.ts
```

1. In the `docs` directory, use `@rspress/core/theme`, which points to your `theme/index.tsx`.

2. In the `theme` directory, use `@rspress/core/theme-original`, which always points to Rspress built-in theme components.

:::

### Wrap: Pass props/slots \{#wrap}

Wrapping means adding props to re-exported components. Here is an example that inserts content before the navbar title:


**theme/index.tsx**

```tsx
import { Layout as BasicLayout } from '@rspress/core/theme-original';
import { useI18n } from '@rspress/core';

const Layout = () => {
  const t = useI18n();
  return <BasicLayout beforeNavTitle={<div>{t('some content')}</div>} />;
};

export { Layout };
export * from '@rspress/core/theme-original';
```


**i18n.json**

```json
{
  "some content": {
    "zh": "一些内容",
    "en": "some content"
  }
}
```


:::tip

The [`Layout`](https://rspress.rs/ui/layout-components/layout.md) component is designed with a series of slot props specifically for wrapping. You can use these props to extend the default theme layout. Click below to preview the slot locations on this page.


:::

### Eject: Directly override the entire component \{#eject}

Ejecting means fully replacing a built-in Rspress component with your own version. Rspress provides the [`rspress eject [component]`](https://rspress.rs/api/commands.md#rspress-eject) command to copy built-in component source code locally so you can modify it directly:

1. Run the CLI. Rspress ejects the specified component source code to the local `theme/components` directory without ejecting its dependencies.

2. Update `theme/index.tsx` re-export:

```tsx title="theme/index.tsx"
// Assuming you ejected the DocFooter component
export { DocFooter } from './components/DocFooter';
export * from '@rspress/core/theme-original';
```

3. Modify `theme/components/DocFooter.tsx` as needed to meet your requirements.

Rspress components are split into fine-grained pieces to make ejecting practical. See which components can be ejected in [Layout Components](https://rspress.rs/ui/layout-components/index.md).

:::warning Do you really need eject?

Ejecting increases maintenance cost. When Rspress is updated, ejected components do not receive updates automatically, so you need to compare and merge changes manually.

Check whether wrapping meets your needs first. Use eject only when wrapping is not enough.

:::
