Skip to content

Markdown rendering

How Display.dev renders Markdown – syntax and reading experience.

On this page

Display.dev renders Markdown to themed HTML on publish. The viewer experience aligns with the Markdown Experience Guidelines (MDXG).

Markdown syntax

Display-flavored Markdown uses CommonMark as its base. Standard syntax works as you'd expect – headings, paragraphs, lists, blockquotes, links, images, inline and fenced code, and horizontal rules. Published pages also support these GFM features:

  • Tables – pipe-delimited, GFM-style.
  • Strikethrough~~text~~.
  • Task lists- [ ] item shows an unchecked box; - [x] item or - [X] item shows a checked box. Published checkboxes are read-only. Change the Markdown and publish an updated version to change their state.
  • Auto-linking – bare URLs and email addresses become clickable links. Wrap a URL in [text](url) only when you want different link text.

Display.dev adds the author notes, highlights, image dimensions, footnotes, math, Mermaid diagrams, and callouts documented below. Published raw HTML follows Display.dev's sanitization rules rather than GFM's raw HTML tag filter. Auto-linking uses Display.dev's supported top-level domain list rather than GitHub's exact recognition rules.

Author notes

Wrap an author note in %% to omit it from the rendered page: Visible text %%check this wording%% continues here.

For notes containing blank lines, put each delimiter on its own line:

markdown
%%
Check the figures before the next update.
 
Confirm the conclusion too.
%%

Unclosed comments and markers inside code stay visible. Escape a marker as \%\% to display it literally. Author notes remain in Markdown source and Copy as Markdown. They are not private and are separate from discussion comments. Existing versions keep their rendered content; publish an updated version to apply this syntax.

Highlights

Wrap text in == to highlight it: ==important text==. You can include emphasis inside a highlight, such as ==**important** text==. Leave no spaces immediately inside the delimiters. Markers inside code remain literal.

Image dimensions

Add |300 to an image description for a width of 300 pixels, or |300x200 for a width and height. Images shrink to fit narrow screens. The size suffix does not appear in the accessible description.

markdown
![Diagram|300](https://example.com/diagram.png)
![Diagram|300x200](https://example.com/diagram.png)

This also works with self-contained Base64 image URLs. Dimensions must be positive whole numbers; invalid suffixes remain part of the description.

Themes

Pick a theme on publish with --theme. Available:

  • github (default)
  • modest
  • pandoc
  • air
  • solarized

Every theme adapts to the viewer's dark-mode preference. The --theme flag has no effect when publishing HTML.

bash
dsp publish report.md --theme pandoc

Heading anchors

Every Markdown heading gets an id derived from its text. A # permalink appears on hover – click it to copy a link to that section:

https://<org>.dsp.so/<shortId>-<slug>#section-title

The id strips punctuation and preserves Unicode letters. Repeated heading text gets a numeric suffix (setup, setup-1). Multi-page documents extend the URL with a page slug.

Raw HTML headings render without these generated ids or permalink controls.

Multi-page documents

An artifact with two or more # H1 headings automatically renders as a multi-page document. A navigation panel on the left titled "On this doc" lists every page, the active page expands to show its outline, and a prev/next footer at the bottom of the page connects them. One # H1 (or none) renders as a single scrolling page.

Display.dev splits on # H1 only, not ## H2. An inline # H1 typically signals a major section, while H2s subdivide a page. Content before the first # H1 becomes an Introduction page.

URLs

In single-page documents the URL fragment is the heading id (#section-title). In multi-page documents it identifies the page:

FragmentBehavior
(none)First page
#<page-slug>Open that page
#<page-slug>--<heading-id>Open that page and scroll to the heading

Old #heading-id bookmarks continue to work – they resolve to the page containing the heading.

Keyboard

  • Arrow Up / Arrow Down move focus through the page list.
  • Enter opens the focused page.
  • Page Up / Page Down move to the previous / next page from anywhere outside form fields.
  • Esc returns focus to the article body.

The top-bar Copy as Markdown button becomes per-page in multi-page documents – see Source export.

Table of contents

Single-page documents with two or more H2 sections get a collapsible table of contents on the left that highlights the current section as you scroll. Don't write your own – Display.dev builds it from H2 and H3 headings.

Multi-page documents replace the TOC with a per-page outline inside the side nav: when a page is active, its H2 and H3 headings expand inline under its row.

Cmd+F (or Ctrl+F) opens an in-document find input that cycles through matches with a counter. In multi-page documents it walks hidden pages too and shows the page name next to each match, so matches outside the active page aren't skipped.

Cmd+K (or Ctrl+K) opens a palette of ranked pages with snippets. The palette is only available in multi-page documents.

Footnotes

[^label] references become superscript links to a footnote section at the bottom of the document. Footnotes can be referenced multiple times; each reference gets a back-link in the definition.

markdown
The migration[^why] took a week.
 
[^why]: Originally scheduled for one day. Estimates remain hard.

A reference with no matching definition renders as literal [^label] text. A definition with no reference is dropped silently.

In multi-page documents, footnote definitions are redistributed per page – each page that references a footnote gets its own copy at the bottom, with back-links pointing to the reference on that page.

Smart punctuation

These character sequences get transformed at publish time:

  • --- → em dash
  • -- → en dash
  • ... → ellipsis
  • (c), (C) → ©
  • (r), (R) → ®
  • (tm), (TM) → ™
  • +- → ±
  • Straight quotes around words → curly quotes

Fenced code blocks bypass the transform – code samples render exactly as typed.

Code blocks

Fenced blocks (```language) render in a monospace block with the theme's background color.

Math (KaTeX)

Wrap math in $…$ for inline, $$…$$ for a centered display block. The LaTeX is rendered to HTML when you publish.

markdown
The loss is $\mathcal{L} = -\sum_i y_i \log \hat{y}_i$.
 
$$
\frac{\partial \mathcal{L}}{\partial z_j} = \hat{y}_j - y_j
$$

Supported: the KaTeX function set. MathML, asciimath, and other math syntaxes are not.

Invalid LaTeX shows as an inline error instead of breaking the page. Prose like $5 fee or It costs $100. is left alone – math only parses when the opening $ has whitespace or punctuation before it and the closing $ has whitespace or punctuation after it. Links inside math (\href) are disabled.

Diagrams (Mermaid)

Fence a block with mermaid and the diagram renders in the viewer's browser. Flowcharts, sequence diagrams, state diagrams, ER diagrams, Gantt charts, and the rest of the Mermaid syntax are supported.

markdown
```mermaid
flowchart LR
  A[Markdown] --> B[Display.dev] --> C[Themed HTML]
```

The diagram follows the page theme. Toggle dark mode and the colors update without a reload.

Invalid syntax shows an error in place of the diagram instead of breaking the page. Clickable links inside diagrams are disabled.

Callouts

Start a blockquote with a type marker and an optional plain-text title:

markdown
> [!tip] Try this
> The body supports **Markdown**.
>
> > [!note]- More detail
> > This nested callout starts collapsed.

Common types include note, info, tip, warning, danger, question, example, and quote. Types are case-insensitive. Unknown types use note styling. Without a title, the type supplies one. Add + after the marker for an initially expanded callout or - for an initially collapsed one; omit both for a callout that stays expanded. Readers can open and close foldable callouts without changing the Markdown. Existing versions keep their rendered content; publish an updated version to apply this syntax.

Raw HTML

HTML is limited to 128 nested elements. An HTML fragment exceeding that depth is omitted from the rendered page; its original source remains available.

Markdown can include sanitized HTML for paragraphs, headings, emphasis, lists, tables, links, code and embedded raster images. Markdown syntax inside a complete HTML element stays literal:

html
<div style="color:teal;text-align:center">
  <strong>HTML formatting works.</strong>
  **These Markdown delimiters stay visible.**
</div>

Inline styles support text and background colors, font weight/style, text decoration, and alignment. Colors use three/six-digit hex or a limited set of named colors. Layout rules, CSS functions and URLs are removed.

Scripts, event handlers, forms, frames, SVG/MathML, IDs, classes, and unsupported attributes are removed from the rendered page. Raw HTML images must use embedded Base64 PNG, JPEG, GIF, WebP or AVIF data; external raw HTML image URLs are removed. Markdown image syntax (![alt](url)) keeps its existing behavior. Safe HTML links work in the published page. The original source remains available for export.

To publish interactive content, create a new HTML artifact. An existing Markdown artifact keeps its format.

What's not supported

A few syntaxes and features from other Markdown viewers aren't supported here:

  • Definition lists – the term / : definition two-line pattern renders as plain text.
  • Embedded media<video>, <audio>, and <iframe> are not supported in Markdown. Create a new HTML artifact to embed media.
  • Code-block syntax highlighting – fenced blocks render as plain monospace. Pre-highlight as HTML and publish that file directly if you need it.
  • Per-block code copy buttons – the in-viewer Copy button copies the complete document or the active page, not individual code blocks.

Source export

Display.dev keeps the original Markdown alongside the rendered HTML. Two ways to get it back:

  • dsp export <shortId> – returns the original Markdown.
  • The Copy button in the viewer's top bar – copies the source to the clipboard. On single-page documents it is labeled Copy as Markdown. On multi-page documents it becomes Copy this page (or Copy intro on the Introduction page), with a secondary Copy whole document link for the full source.

If the artifact was published as HTML, dsp export <shortId> --format markdown converts the HTML back to Markdown.

Was this page helpful?