Skip to content

Writing pages and components

Create pages, organise navigation, and write documentation with Markdown and MDX components.

8 min read

Every page is an .mdx file in src/content/docs/. The file path becomes the URL, so src/content/docs/guides/deploy.mdx is served at /guides/deploy/.

1. Create a page

Add a file with a title in its frontmatter. The title becomes the page heading, so don’t repeat it in the body.

src/content/docs/guides/deploy.mdxmdx
---
title: Deploy
description: Ship the site to production.
---

Run the build, then upload the output.

Frontmatter is validated at build time. A missing title or a misspelled field fails the build with a message that names the file and the field.

  • title is required. Everything else is optional.
  • description appears under the heading, in search results, and in social cards.
  • sidebar controls where the page sits in the navigation.
    • order sorts pages within a group, lowest first.
    • badge adds a short label next to the link.

1.1 Frontmatter fields

Field Type Description
title string The page heading and the <title> tag.
description string One-line summary for search, social cards, and the page header.
sidebar.order number Position within the sidebar group. Lower numbers come first.
draft boolean Builds the page in development only. It never reaches production.

2. Write with Markdown

Standard Markdown works everywhere: bold, italic, links, inline code, lists, tables, and fenced code blocks. Press ⌘ K to search the site for anything else.

Write the page you would want to find. One topic per page, and a title that says what the reader will be able to do.

Code blocks are highlighted at build time. Add a title to show a filename, and line numbers in braces to draw attention to specific lines.

astro.config.tsts
const nimbusConfig = defineNimbusConfig({
  site: "https://docs.example.com",
  title: "My docs",
  description: "Guides and reference for My product.",
});

2.1 Organise the sidebar

Folders become sidebar groups. Inside a group, pages sort by sidebar.order, then by title.

  1. Create a folder in src/content/docs/, for example guides/.
  2. Move related pages into it.
  3. Set sidebar.order on each page to fix the order.

3. Use components

Components are available in every .mdx file without an import. Install more from the registry when you need them.

  1. Add a component

    Run npx @cloudflare/nimbus-docs add accordion to copy it into src/components/ui/.

  2. Register it

    Add it to src/components.ts so every page can use it.

npx @cloudflare/nimbus-docs add accordion
pnpm dlx @cloudflare/nimbus-docs add accordion

3.1 What ships with the starter

Aside
Notes, tips, cautions, and warnings that stand apart from the text.
Steps
Numbered procedures, each with a title and its own content.
Tabs
The same content in several variants, such as one command per package manager.
Can I use plain Markdown files instead of MDX?

Yes. MDX is a superset of Markdown, so any .md content works unchanged in an .mdx file. You only need MDX syntax when you add a component.


Pages you write today keep working when you upgrade Nimbus1. Use highlights sparingly; they lose their meaning when everything is marked.

4. Component reference

Every .mdx file can use these components without an import. Each one is a file in src/components/ui/, so you can change how it looks or works.

4.1 Aside

Set a note, tip, caution, or warning apart from the text around it.

<Aside type="note">
  Pages are validated at build time.
</Aside>

<Aside type="caution" title="Before you deploy">
  Set `site` in `astro.config.ts` to your production URL.
</Aside>
Prop Value
type note (default), tip, caution, or danger
title Text above the content. Defaults to the type’s name.
icon Any ph: icon name, in place of the type’s icon.

For a title with formatting, pass it as a slot: <Fragment slot="title">Uses <code>env</code></Fragment>.

4.2 Steps

Number a procedure. Each step has a title and its own content.

  1. Create the page

    Add src/content/docs/deploy.mdx with a title.

  2. Preview it

    Run npm run dev and open the page.

<Steps>
  <Step title="Create the page">
    Add `src/content/docs/deploy.mdx` with a `title`.
  </Step>
  <Step title="Preview it">
    Run `npm run dev` and open the page.
  </Step>
</Steps>
Prop Value
start on Steps The first step’s number. Defaults to 1.
title on Step The step’s heading. Also accepts a title slot.

4.3 Tabs

Show the same content in several variants. Give tabs a syncKey, and the reader’s choice carries over to every set of tabs with the same key.

Press ⌘ K to search.

Press Ctrl K to search.

<Tabs syncKey="os">
  <TabItem label="macOS">
    Press <kbd>⌘</kbd> <kbd>K</kbd> to search.
  </TabItem>
  <TabItem label="Windows">
    Press <kbd>Ctrl</kbd> <kbd>K</kbd> to search.
  </TabItem>
</Tabs>
Prop Value
syncKey on Tabs Tabs with the same key switch together, and remember the choice.
label on TabItem The tab’s name. Required.

4.4 Package managers

Write an install command once and show it for npm, pnpm, Yarn, and Bun.

npm i your-package
<PackageManagers pkg="your-package" />

Add dev for a dev dependency, or type="run" args="build" for a script.

4.5 Cards

Link readers to the next places to go, in a grid that stacks on small screens.

Write a page

Create an .mdx file in src/content/docs/.

Change the theme

Edit the colour and type tokens in src/styles/globals.css.

<CardGrid>
  <Card title="Write a page" icon="ph:pencil-simple">
    Create an `.mdx` file in `src/content/docs/`.
  </Card>
  <Card title="Change the theme" icon="ph:palette">
    Edit the colour and type tokens in `src/styles/globals.css`.
  </Card>
</CardGrid>
Prop Value
title on Card The card’s heading. Also accepts a title slot.
icon on Card Any ph: icon name. Also accepts an icon slot.

Icons come from Phosphor: use any name with the ph: prefix.

4.6 Partials

Write a passage once and include it on any page. Partials live in src/content/partials/.

This text lives in src/content/partials/example.mdx and is pulled in with <Render file="example" />. Edit the partial once and every page that renders it stays in sync — handy for install steps, support notes, or any boilerplate you’d otherwise copy between pages.

<Render file="example" />

4.7 Restyle any part

Every part of every component has a data-slot attribute, so you can restyle one piece from src/styles/globals.css without editing the component.

src/styles/globals.csscss
[data-slot="card-title"] {
  letter-spacing: -0.01em;
}

Corners come from two tokens in the same file: --nb-radius for cards, callouts, code blocks and buttons, and --nb-radius-sm for the small marks inside them. Change them to re-round the whole site.

4.8 Add more

Accordions, file trees, link cards, embeds, and more install from the registry when you need them. Each one lands as a file in src/components/ui/, like the components above.

npx @cloudflare/nimbus-docs add accordion

5. FileTree

Use a nested Markdown list to describe a directory structure. End directory names with /, highlight important files with **name**, and use ... for omitted entries.

  • src/
    • content/
      • docs/
        • writing-pages.mdx
    • components/
      • ui/
  • astro.config.ts
  • package.json
<FileTree>

- src/
  - content/
    - docs/
      - **writing-pages.mdx**
  - components/
    - ui/
- astro.config.ts
- package.json

</FileTree>

6. Accordion

Use collapsible sections for optional explanations. Set open on an Accordion to start expanded.

Components registered in src/components.ts are available in every MDX article.
Use a partial and the Render component.
<AccordionGroup>
  <Accordion>
    <AccordionTrigger>Do components need imports?</AccordionTrigger>
    <AccordionContent>Components registered in src/components.ts are available in every MDX article.</AccordionContent>
  </Accordion>
  <Accordion>
    <AccordionTrigger>Where should shared text live?</AccordionTrigger>
    <AccordionContent>Use a partial and the Render component.</AccordionContent>
  </Accordion>
</AccordionGroup>

7. CodeGroup

Use titles to label code alternatives. Each fenced block becomes one panel.

<CodeGroup titles={["JavaScript", "TypeScript"]}>

```js
const greeting = "Hello, Petwan";
```

```ts
const greeting: string = "Hello, Petwan";
```

</CodeGroup>

8. CopyPrompt

The text prop supplies the full prompt copied to the clipboard, even if the displayed line is truncated.

Read the Writing pages and components guide, then help me draft a clear MDX article using the installed components.

<CopyPrompt text="Read the Writing pages and components guide, then help me draft a clear MDX article using the installed components." />

9. Embed

Provide src and an accessible title; ratio defaults to 16/9. This local demo avoids depending on an external provider. External sites must permit embedding.

<Embed src="/embed-demo.html" title="Petwan embedded content example" ratio="16/9" />

10. Frame

Wrap a screenshot or demo with a caption. Imported images passed through src use Astro image optimization; public image paths use a plain image.

Petwan letter P logo
The Petwan P mark
<Frame caption="The Petwan P mark">
  <img src="/logo.svg" alt="Petwan letter P logo" width="128" height="128" />
</Frame>

11. LinkCard

Use href, title and an optional description. The entire card is a link.

Petwan Journal

Return to the homepage and browse the latest notes.
<LinkCard href="/" title="Petwan Journal" description="Return to the homepage and browse the latest notes." />

12. Popover

Compose the root, trigger and content. Keep PopoverTrigger a direct child of Popover. Supported placements are bottom-start, bottom-end, top-start and top-end.

Use one clear topic per article and runnable examples.

<Popover>
  <PopoverTrigger class="rounded-md border border-border px-3 py-2 text-sm">Writing tip</PopoverTrigger>
  <PopoverContent placement="bottom-start">
    <p>Use one clear topic per article and runnable examples.</p>
  </PopoverContent>
</Popover>

13. Lightbox

Give a figure a caption and a click-to-zoom surface. Plain Markdown images already zoom, so wrap only when you want an explicit caption.

The Petwan P mark
<Lightbox src="/logo.svg" alt="Petwan letter P logo" caption="The Petwan P mark" />
Prop Value
src Image path. Required.
alt Accessible description. Required.
caption Optional text below the image.
class Extra class on the img element.

14. Math formulas

MathFormula is not registered globally — import it explicitly. The tex prop is a string expression, so backslashes must be escaped as \\.

import MathFormula from "../../components/MathFormula.astro";

<MathFormula tex={"E = mc^2"} display />

A bare $$ … $$ block does not render here: MDX reads the braces as a JSX expression and the build fails. Use the component.

Footnotes

  1. Changes that need your attention are listed by npx @cloudflare/nimbus-docs migrate --dry-run. ↩

Type to search…

↑↓ navigate↵ selectEsc close