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

# Theme config

Theme configuration is defined under `themeConfig`. For example:

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

export default defineConfig({
  themeConfig: {
    // ...
  },
});
```

## nav

- **Type**: `Array`
- **Default**: `[]`

The `nav` configuration is an array of `NavItem` with the following types:

```ts
interface NavItem {
  // Navbar text
  text: string;
  // Navbar link
  link: '/';
  // Whether it is a download link
  download?: boolean;
  // Activation rules for navbar links
  activeMatch: '^/$|^/';
  // Icon displayed before the navbar text
  icon?: string;
  // Tag displayed after the navbar text
  tag?: string;
}
```

`activeMatch` matches the current route. When the route matches the `activeMatch` rule, the nav item is highlighted. By default, `activeMatch` uses the nav item's `link`.

For local icons, place the image in the `public` directory and reference it with an absolute path such as `/icon.png`. Inline SVG strings, emoji, external URLs, and data URLs are also supported.

For example:

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

export default defineConfig({
  themeConfig: {
    nav: [
      {
        text: 'Home',
        link: '/',
        icon: '/icon.png',
      },
      {
        text: 'Guide',
        link: '/guide/',
      },
    ],
  },
});
```

You can also configure multi-level menus in the `nav` array with the following type:

```ts
interface NavGroup {
  text: string;
  // submenu
  items: NavItem[];
  // Icon displayed before the navbar text
  icon?: string;
  // Tag displayed after the navbar text
  tag?: string;
}
```

For example:

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

export default defineConfig({
  themeConfig: {
    nav: [
      {
        text: 'Home',
        link: '/',
      },
      {
        text: 'Guide',
        items: [
          {
            text: 'Getting Started',
            link: '/guide/getting-started',
          },
          {
            text: 'Advanced',
            link: '/guide/advanced',
          },
          // Also supports nested groups
          {
            text: 'Group',
            items: [
              {
                text: 'Personal',
                link: 'http://example.com/',
              },
              {
                text: 'Company',
                link: 'http://example.com/',
              },
            ],
          },
        ],
      },
    ],
  },
});
```

## sidebar

- **Type**: `Object`

Site sidebar configuration. It is an object with the following type:

```ts
// The key is the path of SidebarGroup
// value is an array of SidebarGroup
type Sidebar = Record<string, SidebarGroup[]>;

interface SidebarGroup {
  text: string;
  link?: string;
  items: SidebarItem[];
  // Whether the group can be collapsed
  collapsible?: boolean;
  // Whether to be collapsed by default
  collapsed?: boolean;
  // Icon displayed before the sidebar text
  icon?: string;
  // Tag displayed after the sidebar text
  tag?: string;
}

type SidebarItem = {
  // sidebar text
  text: string;
  // sidebar link
  link: string;
  // Icon displayed before the sidebar text
  icon?: string;
  // Tag displayed after the sidebar text
  tag?: string;
};
```

For example:

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

export default defineConfig({
  themeConfig: {
    sidebar: {
      '/guide/': [
        {
          text: 'Getting Started',
          icon: '/icon.png',
          items: [
            {
              text: 'Introduction',
              link: '/guide/getting-started/introduction',
              icon: '<svg>...</svg>',
              tag: 'new',
            },
            {
              text: 'Installation',
              link: '/guide/getting-started/installation',
            },
          ],
        },
        {
          text: 'Advanced',
          items: [
            {
              text: 'Customization',
              link: '/guide/advanced/customization',
            },
            {
              text: 'Markdown',
              link: '/guide/advanced/markdown',
            },
          ],
        },
      ],
    },
  },
});
```

## footer

- **Type**: `Object`
- **Default**: `{}`

Homepage footer configuration.

The `footer` config is a `Footer` object:

```ts
export interface Footer {
  message?: string;
}
```

`message` is a string that can contain HTML content. This string will be inserted into the footer using `dangerouslySetInnerHTML`, allowing you to pass in HTML template tags to design your footer.

For example:

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

export default defineConfig({
  themeConfig: {
    footer: {
      message:
        '<p>This is a footer with a <a href="https://example.com">link</a> and <strong>bold text</strong></p>',
    },
  },
});
```

## lastUpdated

- **Type**: `boolean | { author?: boolean | ((info: { name: string; email: string; filePath: string }) => string) }`
- **Default**: `false`

Controls whether each doc page shows its last updated time. Rspress reads this value from the file's latest Git commit.

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

export default defineConfig({
  themeConfig: {
    lastUpdated: true,
  },
});
```

When deploying in CI, make sure the Git history is available. For example, use `fetch-depth: 0` with `actions/checkout` on GitHub Actions.

Set `author` to display the last commit author as well. Pass a function to customize the rendered author text.

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

export default defineConfig({
  themeConfig: {
    lastUpdated: {
      author: ({ name, email }) => `${name} <${email}>`,
    },
  },
});
```

## socialLinks

- **Type**: `Array`
- **Default**: `[]`

Add related links, such as GitHub or X links. Related links support five modes: `link`, `text`, `img`, `dom`, and `github-stars`. For example:

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

export default defineConfig({
  themeConfig: {
    socialLinks: [
      {
        icon: 'github',
        mode: 'link',
        content: 'https://github.com/sanyuan0704/island.js',
      },
      {
        icon: 'wechat',
        mode: 'text',
        content: 'wechat: foo',
      },
      {
        icon: 'qq',
        mode: 'img',
        content: '/qrcode.png',
      },
      {
        icon: 'github',
        mode: 'dom',
        content:
          '<img src="https://lf3-static.bytednsdoc.com/obj/eden-cn/rjhwzy/ljhwZthlaukjlkulzlp/rspress/rspress-navbar-logo-0904.png" alt="logo" id="logo" class="mr-4 rspress-logo dark:hidden">',
      },
      {
        icon: 'github',
        mode: 'github-stars',
        content: 'https://github.com/web-infra-dev/rspress',
      },
    ],
  },
});
```

- In `link` mode, clicking the icon opens the link.
- In `text` mode, hovering over the icon displays a tooltip with the configured text.
- In `img` mode, hovering over the icon displays a tooltip with the configured image. The image must be placed in the `public` directory.
- In `dom` mode, pass the HTML string to render directly to `content`. Wrap it in quotes.
- When in `github-stars` mode, `content` should be the GitHub repository URL. The repository's star count is fetched from the GitHub REST API and rendered next to the icon. The result is cached in `localStorage` for one hour to avoid hitting the API rate limit. If the request fails (offline, rate-limited, private repo), the icon falls back to a plain link.

Related links support the following icons via the `icon` field:

```ts
export type SocialLinkIcon =
  | 'lark'
  | 'discord'
  | 'facebook'
  | 'github'
  | 'instagram'
  | 'linkedin'
  | 'slack'
  | 'x'
  | 'youtube'
  | 'wechat'
  | 'qq'
  | 'juejin'
  | 'zhihu'
  | 'bilibili'
  | 'weibo'
  | 'gitlab'
  | 'X'
  | 'bluesky'
  | 'npm'
  | { svg: string };
```

To use a custom icon, pass an object with an `svg` field. The `svg` value is the custom icon content:

```js
import { defineConfig } from '@rspress/core';

export default defineConfig({
  themeConfig: {
    socialLinks: [
      {
        icon: {
          svg: '<svg>foo</svg>',
        },
        mode: 'link',
        content: 'https://github.com/',
      },
    ],
  },
});
```

## nextPageText

- **Type**: `string`
- **Default**: `Next Page`

Text for the next page link. For example:

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

export default defineConfig({
  themeConfig: {
    nextPageText: 'Next Page',
  },
});
```

## locales

- **Type**: `Array<LocaleConfig>`
- **Default**: `undefined`

I18n configuration. This is an array of `LocaleConfig` objects:

```ts
export interface LocaleConfig {
  /**
   * General locale config for site, which will have a higher priority than `locales`
   */
  // language name
  lang?: string;
  // HTML title, takes precedence over `themeConfig.title
  title?: string;
  // HTML description, takes precedence over `themeConfig.description`
  description?: string;
  // Display text for the corresponding language
  label: string;
}
```

`LocaleConfig` contains many of the same options as the theme config, but locale-specific values have higher priority.

## darkMode

- **Type**: `boolean | 'dark' | 'light' | 'auto' | 'force-light' | 'force-dark' | 'force-auto'`
- **Default**: `true`

When dark mode is active, Rspress adds the `dark` class to the `<html>` element. You can use the `html.dark` selector to customize dark mode styles:

```css
html.dark .custom-content {
  color: white;
}
```

Configure the Dark/Light mode behavior:

- `true`: same as `'auto'`.
- `false`: same as `'force-light'`.
- `'light'`: show the toggle button and use light mode by default when the user has no saved preference.
- `'dark'`: show the toggle button and use dark mode by default when the user has no saved preference.
- `'auto'`: show the toggle button and follow the user's system preference by default when the user has no saved preference.
- `'force-light'`: always use light mode and hide the toggle button.
- `'force-dark'`: always use dark mode and hide the toggle button.
- `'force-auto'`: always follow the user's system preference and hide the toggle button.

For example, always use dark mode and hide the toggle button:

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

export default defineConfig({
  themeConfig: {
    darkMode: 'force-dark',
  },
});
```

## editLink

- **Type**:

```ts
interface EditLink {
  /**
   * Custom repository url for edit link.
   */
  docRepoBaseUrl: string;
}
```

- **Default**: `undefined`

Display a link to edit the page on Git management services such as GitHub, or GitLab. The link appears in both the doc footer and the right-side outline panel.

For example:

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

export default defineConfig({
  themeConfig: {
    editLink: {
      docRepoBaseUrl:
        'https://github.com/web-infra-dev/rspress/tree/main/website/docs',
    },
  },
});
```

## enableContentAnimation

- **Type**: `boolean`
- **Default**: `false`

Controls whether page transitions are animated. This is implemented with the [View Transition API](https://developer.mozilla.org/docs/Web/API/View_Transitions_API). For example:

> The animation is not configurable for now.

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

export default defineConfig({
  themeConfig: {
    enableContentAnimation: true,
  },
});
```

## enableAppearanceAnimation

- **Type**: `boolean`
- **Default**: `false`

Controls whether switching between light and dark mode is animated. This is implemented with the [View Transition API](https://developer.mozilla.org/docs/Web/API/View_Transitions_API). For example:

> The animation is not configurable for now.

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

export default defineConfig({
  themeConfig: {
    enableAppearanceAnimation: true,
  },
});
```

## search

- **Type**: `boolean`
- **Default**: `true`

Whether to display the search box. For example:

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

export default defineConfig({
  themeConfig: {
    search: false,
  },
});
```

## enableScrollToTop

- **Type**: `boolean`
- **Default**: `true`

Enables the scroll-to-top button in docs pages. For example:

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

export default defineConfig({
  themeConfig: {
    enableScrollToTop: true,
  },
});
```

## ~~localeRedirect~~

- **Type**: `'auto' | 'never' | 'only-default-lang'`
- **Default**: `'auto'`

Controls how first-time visitors are redirected to the closest configured locale based on `window.navigator.language`.

:::warning Configuration moved

This option has moved to [`route.localeRedirect`](https://rspress.rs/api/config/config-basic.md#routelocaleredirect). `themeConfig.localeRedirect` remains supported for backward compatibility, but is deprecated. Migrate the option to `route`; when both options are set, `route.localeRedirect` takes precedence.

:::

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

export default defineConfig({
  route: {
    localeRedirect: 'never',
  },
});
```

## fallbackHeadingTitle

- **Type**: `boolean`
- **Default**: `true`

Controls whether [`frontmatter.title`](https://rspress.rs/api/config/config-frontmatter.md#title) is used as a fallback when a document has no H1 heading. For example:

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

export default defineConfig({
  themeConfig: {
    fallbackHeadingTitle: false,
  },
});
```

```mdx
---
title: Document Title
---

## Content
```

## llmsUI

- **Type**:

```ts
type LlmsUI =
  | boolean
  | {
      injectLlmsHint?: boolean;
      viewOptions?: false | Array<'markdownLink' | 'chatgpt' | 'claude'>;
      placement?: 'title' | 'outline';
    };
```

- **Default**: `false` (automatically set to `true` when `llms: true` is configured)

Configuration for the llms UI components. When enabled, `LlmsCopyButton` and `LlmsViewOptions` are automatically added below all H1 headings by default, or as rows in the outline panel.

This is useful when using the [llms](https://rspress.rs/guide/basic/ssg-md.md) feature to generate llms.txt files, because users can copy or open Markdown content in AI tools.

:::warning
SSG-MD only runs during builds, so copying Markdown content does not work in `dev` mode. Run `rspress build` first, then debug with `rspress preview`. See [Differences between dev and build](https://rspress.rs/guide/basic/ssg.md#differences-between-dev-and-build) for details.
:::

For example:

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

export default defineConfig({
  llms: true,
  themeConfig: {
    llmsUI: {
      injectLlmsHint: true,
      viewOptions: ['markdownLink', 'chatgpt', 'claude'],
      placement: 'outline',
    },
  },
});
```

### injectLlmsHint


[Added in v2.0.18](https://github.com/web-infra-dev/rspress/releases/tag/v2.0.18)

- **Type**: `boolean`
- **Default**: `true`

This option controls whether an LLM directive hint is injected into generated pages. The same `LlmsHint` component has two output forms:

- In SSG HTML output, it renders a visually hidden plain-text DOM element near the top of the page. It does not use `display: none`, the `hidden` attribute, `aria-hidden`, or nested links, so agent-side HTML-to-Markdown conversion can preserve the directive as text.
- In SSG-MD Markdown output, it renders a blockquote string near the top of the Markdown page.

Assuming [`siteOrigin`](https://rspress.rs/api/config/config-basic.md#siteorigin) is `https://example.com`, the following HTML directive is injected into the `/guide/` page:


```html
<div class="rp-llms-hint" style="position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);clip-path:inset(50%);white-space:nowrap;border:0">For AI agents: the complete documentation index is available at https://example.com/llms.txt, the full documentation bundle is available at https://example.com/llms-full.txt, and this page is available as Markdown at https://example.com/guide/index.md.</div>
```

The SSG-MD Markdown output for the same page starts with:

```md
> For AI agents: the complete documentation index is available at https://example.com/llms.txt, the full documentation bundle is available at https://example.com/llms-full.txt.
```

The URLs automatically include the configured `siteOrigin`, [`base`](https://rspress.rs/api/config/config-basic.md#base), locale, and version prefixes. Without `siteOrigin`, the URLs remain base-aware paths.

Set `injectLlmsHint` to `false` to disable this behavior:

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

export default defineConfig({
  llms: true,
  themeConfig: {
    llmsUI: {
      injectLlmsHint: false,
    },
  },
});
```

### viewOptions

- **Type**: `false | Array<'markdownLink' | 'chatgpt' | 'claude'>`
- **Default**: `['markdownLink', 'chatgpt', 'claude']`

Options for the LlmsViewOptions dropdown menu. Built-in options include:

- `'markdownLink'`: Copy markdown file link
- `'chatgpt'`: Open in ChatGPT
- `'claude'`: Open in Claude

Set `viewOptions` to `false` or `[]` to hide the view options UI.

### placement

- **Type**: `'title' | 'outline'`
- **Default**: `'title'`

Controls where the LLMS UI components are displayed.

- `'title'`: Show as buttons below the H1 title (default behavior)
- `'outline'`: Show as separate rows in the right-side outline panel

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

export default defineConfig({
  llms: true,
  themeConfig: {
    llmsUI: {
      placement: 'outline',
    },
  },
});
```
