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

# 自定义主题


For your Agent

如果你正在使用 Coding Agent，可以安装 [`rspress-custom-theme` Agent Skill](https://github.com/rstackjs/agent-skills#rspress-custom-theme)，让 Agent 帮你生成一个全新的主题。
如果想了解更多 Rspress AI 辅助开发能力，请查看 [AI 页面](https://rspress.rs/zh/guide/start/ai.md)。

1. 对于 CSS，Rspress 提供了 [CSS 变量](#css-variables) 和 [BEM 类名](#bem-classname)进行定制。

2. 对于 JS / React，Rspress 基于 ESM 重导出覆盖实现了一套运行时接口，支持对内置组件进行修改或替换，实现自己的首页、侧边栏、搜索组件等。

   在此之上有两种使用模式：

   - [**wrap**](#wrap)：通过 props / 插槽来对 Rspress 内置的组件进行 **包装** 并增强。
   - [**eject**](#eject)：直接 **覆盖** 整个组件，可以使用 [`rspress eject`](https://rspress.rs/zh/api/commands.md#rspress-eject) 命令将源码拷贝到本地直接修改并覆盖。

下面会根据主题定制化的程度会依次进行介绍。

## CSS 变量 \{#css-variables}

Rspress 暴露了一些常用的 CSS 变量，相比重写 Rspress 内置的 React 组件，覆盖 CSS 变量实现定制化更简单也更易维护。你可以在 [UI - CSS 变量](https://rspress.rs/zh/ui/vars.md) 页面查看这些 CSS 变量，并复制到项目中进行样式覆盖，例如：

```tree
├── docs
│   └── index.mdx
├── theme
│   ├── index.tsx
│   └── index.css  <-- 复制 CSS 变量代码到这里来进行样式覆盖
└── rspress.config.ts
```

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

另一种方式是使用 `rspress.config.ts` 中的 [globalStyles](https://rspress.rs/zh/api/config/config-basic.md#globalstyles) 配置：

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

export default defineConfig({
  globalStyles: path.join(__dirname, 'styles/index.css'), // 指向你创建的 CSS 文件
});
```

## BEM 类名 \{#bem-classname}

Rspress 内置组件均使用 BEM 命名规范。你可以使用这些类名进行样式覆盖，覆盖方式和 [CSS 变量](#css-variables) 一致。

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

例如：

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

## 使用 ESM 重导出覆盖内置组件 \{#reexport}

默认情况下，你需要在项目根目录下创建一个 `theme` 目录，然后在 `theme` 目录下创建一个 `index.ts` 或者 `index.tsx` 文件，该文件用于导出主题组件。

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

你可以使用 `@rspress/core/theme-original` 的内置组件，来编写 `theme/index.tsx` 文件:

```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]
```

通过 **ESM 重导出** 覆写内置的组件，所有 Rspress 内部引用的内置组件都会优先使用你重导出的版本。

:::note 关于 @rspress/core/theme-original

`@rspress/core/theme-original` 用于避免循环引用，仅在自定义主题的时候使用。

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

1. `docs` 目录下，使用 `@rspress/core/theme`，`@rspress/core/theme` 指向你的 `theme/index.tsx`。

2. `theme` 目录下，使用 `@rspress/core/theme-original`，`@rspress/core/theme-original` 永远指向 Rspress 内置的主题组件。

:::

### Wrap：传 props/插槽 \{#wrap}

Wrap 指在重导出的组件上增加 props。下面是一个例子，在导航栏标题前面插入一些内容：


**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

[`Layout`](https://rspress.rs/zh/ui/layout-components/layout.md) 组件设计了一系列的插槽 props 专门用于 wrap，你可以通过这些 props 来扩展默认主题的布局。点击下方按钮，在当前页面预览各个插槽的位置。


:::

### Eject：直接覆盖整个组件 \{#eject}

Eject 指将 Rspress 单个内置组件直接进行覆盖，全部使用自己的版本。对此 Rspress 提供了 [`rspress eject [component]`](https://rspress.rs/zh/api/commands.md#rspress-eject) 命令将内置组件的源码拷贝到本地并直接改动，步骤如下：

1. 执行 CLI ，Rspress 会将指定组件的源码 eject 到本地 `theme/components` 目录，不会 eject 依赖。

2. 更新 `theme/index.tsx` 重导出：

```tsx title="theme/index.tsx"
// 假设你 eject 了 DocFooter 组件
export { DocFooter } from './components/DocFooter';
export * from '@rspress/core/theme-original';
```

3. 任意修改 `theme/components/DocFooter.tsx`，使它满足你的需要。

为了方便用户 eject，Rspress 的组件经过细粒度的拆分，你可在 [布局组件](https://rspress.rs/zh/ui/layout-components/index.md) 中看到哪些组件适合 eject。

:::warning 你是否真的需要 eject？

eject 会增加一定的维护成本，因为 Rspress 未来版本更新时，这些被 eject 的组件不会自动获得更新，你需要手动对比并合并变更。

请先查看 wrap 能否满足你的需求，只有在 wrap 无法满足你的需求时，才考虑 eject。

:::
