Writing pages

Every file under pages/ is a route. The Markdown body is rendered with CommonMark + GitHub-flavored extensions (tables, strikethrough, task lists, footnotes, definition lists, heading anchors), and fenced code is highlighted server-side, so it ships as static HTML with no client JS.

Frontmatter #

YAML frontmatter controls the page metadata and its place in the sidebar:

---
title: Sales Overview
sidebar_label: Home
sidebar_position: 1
icon: "🏠"
---
Key Effect
title Page title (browser tab, breadcrumb, search).
sidebar_label Label in the nav tree (defaults to the title).
sidebar_position Sort order within its nav group.
icon Emoji/glyph shown next to the nav label.

Readers can collapse the sidebar on desktop, and a project with a single page hides the nav entirely — tune both with the sidebar: config block.

Dynamic pages ([param] routes) #

A file or directory named [param] captures one URL segment as a route parameter, so a single page serves a whole collection. A file named [id].md matches /customers/5, /customers/42, … and the captured value is available to SQL as ${id}:

<!-- pages/customers/[id].md  →  /customers/<id> -->
:::query name=customer connector=main
SELECT customer_id, name, plan, monthly_spend
FROM customers
WHERE customer_id = ${id}
:::

<Table data={customer} />

A directory works the same way (pages/customers/[id]/index.md), and you can nest them. Matching prefers the most specific route — an exact file or directory wins over a [param] one. Route params flow through the same context-aware substitution as every other ${...}, so they're injection-safe (see Queries).

Tip

To build the full list → click a row → detail drill-down (with clickable table rows via row_link), see Detail pages — it has a live demo.

Note

Dynamic pages have no single enumerable URL, so they're left out of the sidebar nav and — by default — skipped by dashdown build. To export them statically, add a static_paths frontmatter block: a query whose rows enumerate the [param] values, and the build pre-renders one page (and one data snapshot) per row. Without it they need the live server (or a static host that can route a [param] template). See Exporting.

Callouts #

Five callout containers are available with the ::: syntax:

Note

A :::note container — neutral context.

Tip

A :::tip — a helpful aside.

Warning

A :::warning — proceed carefully.

:::tip
A helpful aside.
:::

Mermaid diagrams #

A ```mermaid fenced code block renders as an SVG diagram client-side and fully offline — the Mermaid bundle is vendored and lazy-loaded only on pages that contain a diagram, and every diagram re-themes itself when the reader toggles light/dark. There is no data API and no CDN, so diagrams render identically on the dev server, in a dashdown build export, and inside an embed. Sequence, flowchart, entity-relationship, state, class, Gantt, and pie diagrams are all supported.

For example, this sequence diagram of how a page fetches its data — written as:

```mermaid
sequenceDiagram
    participant B as Browser
    participant S as Dashdown
    participant C as Connector
    B->>S: GET /sales
    S-->>B: HTML (charts empty)
    B->>S: GET /_dashdown/api/data/revenue
    S->>C: run SQL
    C-->>S: rows
    S-->>B: { columns, rows }
    Note over B: ECharts paints the chart
```

…renders as:

sequenceDiagram
    participant B as Browser
    participant S as Dashdown
    participant C as Connector
    B->>S: GET /sales
    S-->>B: HTML (charts empty)
    B->>S: GET /_dashdown/api/data/revenue
    S->>C: run SQL
    C-->>S: rows
    S-->>B: { columns, rows }
    Note over B: ECharts paints the chart

Images & downloadable files #

Add assets to a page and reference them like any Markdown link — they resolve the same way on the dev server and in a dashdown build export.

Co-located — drop a file next to the page's .md under pages/ and reference it relative to the page:

<!-- pages/report.md  +  pages/chart.png  +  pages/files/2024.csv -->
![Revenue](chart.png)

[Download the dataset (CSV)](files/2024.csv)

Shared — put files used across many pages in the project's assets/ folder (served at /assets/) and reference them with a leading /assets/:

![Logo](/assets/logo.svg)

<a href="/assets/whitepaper.pdf" download>Download the whitepaper</a>

Any file type works — images, PDFs, CSVs, zips. Plain Markdown sizes an image to its natural width; use raw HTML to control size or force a download:

<img src="/assets/diagram.png" width="480" alt="Architecture" />
<a href="files/export.zip" download>Download</a>

Here is the shared /assets/dashdown-icon.svg rendered inline at 56px:

Dashdown

Note

You write one natural reference; Dashdown rewrites it to the right form for each target — an absolute URL on the dev server, a root-relative URL (resolved against the page's <base>) in a static export, so it also works when the build is hosted under a sub-path. Co-located refs are confined to pages/ and the .md source itself is never served.

Includes (partials) #

Factor shared Markdown into partials/ and pull it into any page with an {% include %} directive naming the file (path relative to the project root) — the call-to-action at the bottom of the home page is the partial partials/cta.md pulled in this way. Included files are themselves expanded, so partials can include other partials.

Generated