skip to content

In VitePress 1.6, how would you write a component page that shows its real source file, tabbed install commands and a warning box without copying code by hand?

level: middleimportance: should knowfreq 20%

answer

  1. three angle brackets and an at
  2. regions and highlighted lines
  3. a container that makes tabs
  4. colon fences for callouts
  5. frontmatter tunes the layout

basics

~20 s

Import the demo file as a code block with <<< @/demos/ButtonBasic.vue, group the npm, pnpm and yarn fences in a ::: code-group container, and add a ::: warning container. Frontmatter such as outline and editLink tunes the page.

solid answer

~50 s

VitePress extends Markdown for exactly this. `<<< @/demos/ButtonBasic.vue` embeds a file's contents as a highlighted code block, where `@` is the source root; you can add a VS Code region (`#usage`) to show part of a file and `{2,5-7}` to highlight lines, so the sample always matches the demo you render with `<ButtonBasic />`. A `::: code-group` container turns the fences inside it into tabs, each titled by a label such as `[npm]` after the language, and imported snippets can go inside it too. Callouts use custom containers, `::: tip`, `::: warning`, `::: danger`, `::: details`, or GitHub-style alerts like `> [!WARNING]`. Shared text such as an accessibility note can be pulled in with `<!--@include: ./parts/a11y.md-->`. Frontmatter then shapes the page in the default theme: `outline` for heading depth, `aside`, `editLink`, `lastUpdated`, or `layout: page` for a bare canvas.

code

md · 20 lines
md
---
title: Button
outline: [2, 3]
---

<script setup>
import ButtonBasic from './demos/ButtonBasic.vue'
</script>

# Button

<ButtonBasic />

::: details Source
<<< @/demos/ButtonBasic.vue{3}
:::

::: warning
Icon-only buttons need an aria-label.
:::

go deeper

for a junior

Recall the custom containers such as tip and warning, and that frontmatter at the top of a page sets its title and layout.

for a middle

Explain snippet imports with @, regions and line highlighting, code groups, and the default theme's per-page frontmatter keys.

for a senior

Show how you design component pages so every code sample is imported from real files and cannot drift from the demos.

for a principal

Set authoring conventions for contributors, such as demo folder layout, regions and shared includes, so a growing docs site stays consistent.

## The page you are building A component page in a UI library's docs typically has four parts: a live demo, the demo's source, installation commands for several package managers, and caveats. The mistake to avoid is pasting the demo's code into a fence, because the pasted copy drifts from the real file. VitePress's Markdown extensions let the page reference files instead. ## Showing real source: snippet imports `<<< @/demos/ButtonBasic.vue` reads the file at build time and renders it as a fenced code block with syntax highlighting. - **`@` is the source root**: the project root unless `srcDir` is set. Relative paths such as `<<< ../demos/ButtonBasic.vue` also work. - **Regions** show part of a file: mark it with VS Code region comments and write `<<< @/demos/ButtonBasic.vue#usage`. - **Line highlighting** goes in braces: `<<< @/demos/ButtonBasic.vue{2,5-7}`. - **The language** can be set in the braces when the extension is ambiguous. Combined with a component import, the page renders the demo and shows its exact source, so they can never disagree. ## Tabs: code groups A `::: code-group` container turns the fenced blocks inside it into tabs, each titled by the text in square brackets: ````md ::: code-group ```sh [npm] npm add nimbus-ui ``` ```sh [pnpm] pnpm add nimbus-ui ``` ::: ```` Snippet imports work inside code groups as well, with the file name as the default tab title. ## Callouts: containers and alerts | Syntax | Renders | |---|---| | `::: tip`, `::: info` | a neutral or positive callout | | `::: warning`, `::: danger` | a caution callout | | `::: details` | a collapsible block, useful for long source | | `::: warning Custom title` | the same callout with your own title | | `::: raw` | a `vp-raw` wrapper marking a demo as outside the doc content; full style isolation needs the opt-in `postcssIsolateStyles()` | | `> [!WARNING]` and other GitHub-style alerts | rendered like the containers | ## Other extensions worth knowing - **Markdown inclusion**: `<!--@include: ./parts/a11y.md-->` pulls another Markdown file into the page, which suits shared notes repeated across components. - **Custom heading anchors**: `## Props {#props}` fixes the anchor so links survive a heading rename. - **Table of contents**: `[[toc]]` inserts one in the page. - **Code block annotations**: comments such as `// [!code focus]`, `// [!code ++]` and `// [!code --]` focus lines or colour them as a diff, and `:line-numbers` after the language turns on numbering. ## Frontmatter for the page Frontmatter is YAML at the top of the page. Some keys work in any theme, most shape the default theme: | Key | Effect | |---|---| | `title`, `description` | page title and meta description | | `layout` | `doc` (default), `home` or `page` | | `outline` | heading levels in the on-page outline, such as `[2, 3]` or `deep` | | `aside` | show, hide or move the right-hand aside | | `editLink`, `lastUpdated` | toggle those footer features per page | | `sidebar`, `navbar` | hide them on this page | | `pageClass` | add a class for page-specific CSS | ## Putting it together 1. Frontmatter with `title` and `outline: [2, 3]`. 2. A `<script setup>` import of the demo and a `<ButtonBasic />` tag. 3. `<<< @/demos/ButtonBasic.vue` inside a `::: details` block. 4. A `::: code-group` of install commands. 5. A `::: warning` about a known limitation. Every piece of code on the page is either rendered or imported from the same files, so updating the demo updates the docs. ## Why this matters more than it looks In a component library, documentation drift is the most common docs bug: a prop is renamed, the demo is updated because it would not compile otherwise, but the pasted sample in the prose keeps the old name. Readers copy the sample and it fails. Snippet imports make that class of bug impossible for the code shown, because the sample is the demo file. The same idea applies to shared prose. An accessibility note that applies to every form control, pulled in with `<!--@include: -->`, is fixed once instead of in twelve places. Stable heading anchors such as `{#props}` mean links from issues and other pages survive when a heading is reworded. ## Limits to know - Snippet imports display code; they do not type-check it. Keep demos in the build so broken code fails there. - Line highlight ranges refer to line numbers in the file or region, so they shift when the file changes; regions are more robust than raw line ranges. - Container titles and alert types are fixed vocabulary; custom styling needs CSS in the theme.

  • How do you show only the usage part of a long demo file on the page?
    Wrap that part of the file in VS Code region comments, for example `// #region usage` and `// #endregion usage`, and import it with `<<< @/demos/ButtonBasic.vue#usage`. Only the region is shown, and it still updates whenever the file changes.
  • What is the difference between <<< and <!--@include: --> in VitePress Markdown?
    `<<<` imports a file as a code block to display it. `<!--@include: ./parts/a11y.md-->` includes another Markdown file's content into the page as Markdown, so its headings, containers and links are rendered as if written there.

saying these in an interview costs you the question

  • <<< @/demos/ButtonBasic.vue renders the component live on the page.
  • @ in snippet imports always points at the .vitepress folder.
  • Tabs for install commands need a custom Vue tabs component.
  • GitHub-style alerts are shown as plain blockquotes in VitePress.
  • Frontmatter layout: page keeps the doc layout's outline and edit link.