Skip to content

feat(theme): render labels as inline markdown - #5390

Open
dev-itsheng wants to merge 1 commit into
vuejs:mainfrom
dev-itsheng:main
Open

feat(theme): render labels as inline markdown#5390
dev-itsheng wants to merge 1 commit into
vuejs:mainfrom
dev-itsheng:main

Conversation

@dev-itsheng

Copy link
Copy Markdown

Description

Default theme label fields such as sidebar and nav item text are currently rendered with v-html. This is intentional and useful because it lets users write labels such as <code>foo</code>, but it also makes common technical labels easy to get wrong.

For example, a sidebar label like this looks like plain text in config:

text: 'Vue <script setup>'

However, it is rendered into the SSR HTML as raw HTML:

<h3 class="text">Vue <script setup></h3>

The browser parses <script setup> as a real script tag before the client runtime can hydrate the page. This can break the rest of the HTML and the injected site data script, causing follow-up errors such as Cannot read properties of undefined (reading 'locales') or Cannot read properties of undefined (reading 'cleanUrls').

This PR keeps the existing raw HTML capability and adds inline Markdown rendering for default theme label fields on the Node side, before the theme receives site data.

With this change, users can write technical labels in the natural Markdown form:

text: 'Vue `<script setup>`'

and VitePress resolves it to safe HTML:

Vue <code>&lt;script setup&gt;</code>

The new resolver currently covers the default theme fields that are rendered as labels:

  • themeConfig.nav[*].text, including nested nav items
  • themeConfig.sidebar[*].text, including multi-sidebar configs and nested sidebar items
  • themeConfig.sidebar[*].docFooterText
  • themeConfig.docFooter.prev
  • themeConfig.docFooter.next
  • locale themeConfig
  • additionalConfig[*].themeConfig and functional additionalConfig

The transformation is done in resolveSiteData, so SSR, dev, and client navigation share the same resolved site data. This also avoids bringing Markdown rendering into the client bundle or changing multiple default theme Vue components.

Existing HTML labels continue to work. For example:

text: '<code>foo</code>'

still resolves to:

<code>foo</code>

This PR does not escape raw HTML. A label like Vue <script setup> is still treated as raw HTML by design. When users want to display literal angle brackets, they should wrap the syntax in inline code:

text: 'Vue `<script setup>`'

or write explicit HTML entities:

text: 'Vue &lt;script setup&gt;'

The main behavior change is that Markdown inline syntax in these labels is now rendered. For example, **Guide** becomes <strong>Guide</strong>. Since these fields already support raw HTML and VitePress 2 is currently in alpha, this seems like a reasonable time to complete the Markdown part of the original request.

Tests added for:

  • rendering inline Markdown in nav, nested nav, sidebar, nested sidebar, docFooterText, and docFooter
  • preserving existing raw HTML labels
  • resolving locale themeConfig
  • resolving object and functional additionalConfig
  • e2e verification that sidebar labels render the expected innerHTML

Locally verified with:

pnpm exec vitest run -r __tests__/unit node/config.test.ts
pnpm -F=tests-e2e test multi-sidebar/index.test.ts
pnpm exec prettier --experimental-cli --check src/node/config.ts src/node/themeConfig.ts types/default-theme.d.ts __tests__/unit/node/config.test.ts __tests__/e2e/.vitepress/config.ts __tests__/e2e/multi-sidebar/index.test.ts __tests__/e2e/theme-labels/index.md docs/en/reference/default-theme-config.md docs/en/reference/default-theme-nav.md docs/en/reference/default-theme-sidebar.md
git diff --check
pnpm build

Linked Issues

Related to #1486.

Builds on #1489.

Additional Context

#1486 requested two related capabilities for sidebar item labels:

  • allow Markdown in SidebarItem.text
  • allow HTML strings in SidebarItem.text

#1489 closed that issue by switching sidebar group headings and sidebar item text from Vue text interpolation to v-html, which made raw HTML labels work. That behavior is still useful and this PR intentionally keeps it.

The remaining gap is the Markdown part of the original request. Today, a user can write:

text: '<code>foo</code>'

but cannot write the more natural Markdown equivalent:

text: '`foo`'

This PR completes that missing piece while preserving the HTML support introduced by #1489.

This also avoids changing the public text field name. A rename would be a larger API migration and would not fully solve the ambiguity by itself. The smaller compatibility-preserving change is to keep text, keep HTML support, and render inline Markdown before the default theme consumes the label strings.


Tip

The author can publish a preview release by commenting /publish after creating the PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant