Writing Richer Tutorials with MDX Components
Monograph renders posts as MDX. Here is what that unlocks for tutorials: callout boxes and tabbed code samples, written like this article.

Plain Markdown is fine for prose, but tutorials usually need more: a warning that stands apart from the surrounding paragraph, or install steps that differ by package manager. Posts in src/content/posts can now be .mdx files, which means a post can drop in components alongside regular Markdown without any extra imports.
This article is itself an .mdx file, and every box below is real output, not a screenshot.
Textual Elements
One should not use # Heading 1 for a post.
Heading 2
Use this for major sections within a post. It creates clear breaks that also show up well in the table of contents.
Heading 3
Use this for subsections inside a Heading 2. It is handy for grouping related steps or options under one larger topic.
Heading 4
Use this sparingly for fine-grained labels inside a subsection, like naming a single option or edge case.
Text
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Bold text, italic text, and inline code.
An internal link and an external link.
Lists
Use unordered lists for related options with no strict order, and ordered lists when the sequence matters, like step-by-step instructions.
- Unordered item one
- Unordered item two
- Nested item
- Unordered item three
- Ordered step one
- Ordered step two
- Ordered step three
Quote
Use a quote to pull in an outside voice, highlight a key takeaway, or set apart a passage worth re-reading slowly.
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio praesent libero.
Second paragraph inside the same quote.
Table
Use a table for small, structured comparisons where rows and columns make the differences easier to scan than prose.
| Syntax | Result |
|---|---|
**bold** | bold |
`code` | code |
[link](/) | link |
Callouts
Use <Callout> to flag something the reader shouldn’t skim past. The type prop picks the color and default label; title overrides the label if you need something more specific.
Tabbed code samples
Use <CodeGroup> with <CodeGroupItem> children to show the same step across a few variants, like package managers, without repeating the surrounding prose three times.
npm
npm install
npm run devpnpm
pnpm install
pnpm devyarn
yarn install
yarn devThe tabs are progressive enhancement: a small inline script builds the tab list and hides the inactive panels on load. Without JavaScript, every panel still renders in order with a visible label, so the content stays readable either way.
Syntax highlighting
Ordinary fenced code blocks don’t need a component at all. Markdown and MDX posts both render through Shiki with a dual light/dark theme, so a plain code block already follows whichever color mode the reader has picked:
export function greet(name: string) {
return `Hello, ${name}`;
}
Where the components live
Both components are plain .astro files in src/components/mdx, styled with the same tokens as the rest of the theme, so they pick up light and dark mode automatically. Add more the same way: build the .astro component, then make it available to posts through the components prop passed to <Content /> in src/pages/post/[slug].astro.