Esc

Start typing to search the docs

Writing Content

Frontmatter, sidecar metadata, GFM, and code blocks.

4 min read · 607 words

Authoring model

Use plain markdown (.md) for most pages, and switch to .svx only when a page needs a live Svelte component inline. Everything else about the two file types is identical: frontmatter, sidecars, GFM, code blocks.

Frontmatter

Set page metadata directly in the file with YAML frontmatter; no sidecar file is required:

content/example.md
---
title: Example Page
description: Shown in listings and the meta description tag.
order: 5
tags: [guide]
icon: rocket
---

Your content starts here.

Metadata fields

  • title: Display title
  • description: Optional summary for listings
  • order: Sorting number for nav
  • tags: Optional list for future filtering
  • icon: Name from the curated icon set, shown in the sidebar and next to the page’s <h1>. See Components for the full list of names.

Pages also show a “Last updated on” date, taken from the file’s most recent git commit at build time — not from filesystem timestamps, which reset on every fresh clone. There’s nothing to set: commit the file and the date follows. If your CI does a shallow clone (GitHub Actions and Cloudflare default to one), most files have no reachable history and the date is simply omitted; fetch full history to get it back (fetch-depth: 0 in the GitHub Pages workflow).

Sidecar overrides

A name.meta.json file next to name.md takes priority over frontmatter for any field it sets. That’s useful when you want to tweak nav ordering without touching the prose file, or for content synced in from elsewhere:

content/example.meta.json
{
	"order": 1
}

Frontmatter still supplies everything the sidecar doesn’t override. _meta.json, a separate folder-level file, sits above both; see Navigation for how that precedence works.

Headings

Use consistent heading levels so TOC generation and anchor links are predictable.

GFM formatting

Tables, task lists, strikethrough, and bare-URL autolinks all work out of the box:

FeatureSyntax
Tablepipe-delimited
Task list- [ ] todo
Strikethrough~~done~~
  • Ship GFM support
  • Ship more of the roadmap

Code blocks with a filename

Add filename="..." to a fence’s info string to show a filename header above the code, alongside the built-in copy button every code block gets:

```sh filename="deploy.sh"
echo hello
```

Diagrams and math

Mermaid diagrams use a ```mermaid fence and render to inline SVG:

```mermaid
graph LR
  A[content/*.md] --> B[mdsvex]
  B --> C[page]
```

Mermaid’s layout engine needs a real browser, so instead of driving a headless Chromium at build time, the diagram renders in the reader’s browser. The mermaid library loads lazily and only on pages that actually contain a diagram; every other page ships none of it, and builds need no browser anywhere — locally, in Docker, or in CI. Diagrams pick the dark or light theme active when the page loads.

LaTeX math uses $inline$ and $$block$$ syntax, rendered via KaTeX to static HTML at build time — no client-side JS ships for it:

Inline: $E = mc^2$.

Block:

$$
t = maxleft(1, leftlceil rac{w}{200} \right\rceil\right)
$$

Obsidian syntax

Wikilinks ([[Page]]), image embeds (![[diagram.png]]), > [!tip] callouts, ==highlights==, and %% comments %% all work in .md and .svx files, and publish: false or draft: true in frontmatter keeps a page out of the build. That means content/ can be opened directly as an Obsidian vault; see Obsidian.

Components

.svx files (not .md) can import and use Svelte components inline. See the Components page for the full built-in set (Callout, Tabs, Steps, Cards, Collapse, Bleed, Banner, FileTree, ImageZoom) and how to import them.

Watch out: don’t put inline code containing < or { in a heading — plain inline code and inline code anywhere else on the page are both fine. See Troubleshooting for why.