# Samples

Each sample shows its Markdown next to the output, rendered when this site was built by the same library you would install. In your browser, KaTeX typesets the math and Mermaid draws the diagrams, and the last sample is a live editor; everything else is static HTML.

[Podcast rundown](podcast.md): a complete custom-plugin sample with a split editor, participant completion, planned durations and linked documents. [Implementation guide](docs/podcast.md).

## CommonMark basics

Headings, emphasis, links, nested lists, block quotes, code, entities and escapes: the core alone, no plugins. Raw HTML stays text because `html` is off by default.

```js
createMarkdown()
```

````markdown
# A first-level heading

A paragraph with *emphasis*, **strong emphasis**, `inline code` and a
[link with a title](https://commonmark.org "CommonMark"). Adjacent lines
make one paragraph; two trailing spaces  
make a hard line break.

## Lists

1. Ordered lists
2. may contain
   - bullet lists,
   - nested

- A [reference link][spec]
- An autolink: <https://spec.commonmark.org/0.31.2/>
- Entities: &copy; &mdash; &frac12;
- Escapes: \*not emphasis\*

> A block quote can hold **any** block.
>
> ```js
> const md = createMarkdown()
> ```

    Code indented by four spaces.

***

<b>Raw HTML</b> stays text: the `html` option is off by default.

[spec]: https://spec.commonmark.org "The CommonMark spec"
````

## GitHub Flavored Markdown

Aligned tables, task lists, strikethrough, extended autolinks, footnotes and GitHub alerts, with `gfm()`.

```js
createMarkdown({ plugins: gfm() })
```

```markdown
## Tables

| Syntax | Markdown | Result |
|:--|:--:|--:|
| Emphasis | `*a*` | *a* |
| Strong | `**a**` | **a** |
| Strikethrough | `~~a~~` | ~~a~~ |

## Task lists

- [x] CommonMark 0.31.2
- [x] GFM extensions
- [ ] Your plugin

## Strikethrough and autolinks

The ~~old~~ new renderer. Links without brackets: www.commonmark.org,
https://github.github.com/gfm/ and an address like info@example.com.

## Footnotes

Parsing stays linear on adversarial input.[^adversarial]

[^adversarial]: Checked by `test/pathological.test.ts` in the repository.

## Alerts

> [!NOTE]
> Alerts are blockquotes whose first line is `[!KIND]`.

> [!TIP]
> Neutral colors derive from `currentColor`.

> [!WARNING]
> `tagfilter` is not a sanitizer.
```

## Math with KaTeX

The `math` plugin outputs `\(…\)` and `\[…\]`, the default delimiters of KaTeX auto-render: here KaTeX typesets the formulas in the browser with no configuration.

```js
createMarkdown({ plugins: [math()] })
```

```markdown
Euler's identity, $e^{i\pi} + 1 = 0$, sits in a line of text.
Double dollars make display math: $$\sum_{k=1}^{n} k = \frac{n(n+1)}{2}$$

$$
\int_0^1 x^2 \, dx = \frac{1}{3}
$$

$$
\begin{pmatrix} a & b \\ c & d \end{pmatrix}
\begin{pmatrix} x \\ y \end{pmatrix}
=
\begin{pmatrix} ax + by \\ cx + dy \end{pmatrix}
$$

Prices like $5 and $6 stay text: a dollar sign after a space never
closes the math.
```

## Mermaid diagrams

The `mermaid` plugin turns ```` ```mermaid ```` fences into `<pre class="mermaid">`. Here `renderMermaid()` loads Mermaid only because this page has diagrams, and themes them from the `--md-*` tokens: switch the color scheme and they are redrawn. Without JavaScript you would see the source.

```js
createMarkdown({ plugins: [mermaid()] })
```

````markdown
How mdlib-pure turns Markdown into HTML:

```mermaid
flowchart TD
  src[Markdown] --> parse[Block and inline parsers]
  parse --> ast[(AST)]
  ast -->|plugins| transforms{{Transforms}}
  transforms --> vnodes[VNodes]
  vnodes --> html[HTML string]
  vnodes --> dom[DOM nodes]
```

And who calls whom when a page renders a diagram:

```mermaid
sequenceDiagram
  participant Page
  participant mdlib as mdlib-pure
  participant Mermaid
  Page->>mdlib: renderTo(el, markdown)
  mdlib-->>Page: <pre class="mermaid">
  Page->>mdlib: renderMermaid(el, { load })
  mdlib->>Mermaid: load(), only if there are diagrams
  Mermaid-->>Page: SVG, colored from the tokens
```
````

## Definition lists

Terms and definitions, Pandoc and PHP Markdown Extra style, rendered as `<dl>`, `<dt>` and `<dd>`.

```js
createMarkdown({ plugins: [deflist()] })
```

```markdown
CommonMark
: The reference specification of Markdown syntax.

GFM
: GitHub Flavored Markdown: CommonMark plus tables, strikethrough,
  autolinks, task lists, footnotes and alerts.

Parser
Renderer
:   Two names, two phases of the same job.

    A second paragraph, indented to the content column.
```

## Containers

Fenced `:::` blocks with a kind and an optional title, nestable with longer fences. The kind becomes the class `md-container-KIND`; the look is up to the site.

```js
createMarkdown({ plugins: [container()] })
```

```markdown
::: note
A container without a title takes any block, **even** lists:

- one
- two
:::

::: warning Before you publish
Run `npm run verify`.
:::

:::: details Nested containers
To nest, use more colons on the outside.

::: tip
A container inside another one.
:::
::::
```

## Highlighted text

`==text==` becomes `<mark>`, with the flanking rules of emphasis. A `==` line under a paragraph is still a setext heading.

```js
createMarkdown({ plugins: [mark()] })
```

```markdown
==Highlighted== text becomes `<mark>`, with the same rules as
emphasis: it nests in **==strong==** and *==emphasis==*, and works
inside wo==r==ds too.

These stay text: =one=, ===three===, and == with spaces ==.

A setext heading
==
```

## Front matter

YAML or TOML metadata at the top of a document: kept out of the output, readable with `getFrontmatter()`.

```js
createMarkdown({ plugins: [frontmatter()] })
```

```markdown
---
title: Release notes
date: 2026-10-28
tags: [markdown, commonmark]
---

# Front matter is not rendered

The YAML block at the top stays out of the HTML: `getFrontmatter(root)`
returns its raw text, with no YAML parser (zero dependencies).
```

`getFrontmatter(md.parse(source))` returns:

```json
{
  "type": "yaml",
  "value": "title: Release notes\ndate: 2026-10-28\ntags: [markdown, commonmark]"
}
```

## Syntax highlighting hook

The `highlight(code, lang, meta)` option takes any highlighter. This site uses a tokenizer of a few lines that returns VNodes, so the output stays on the safe path of `renderTo()`.

```js
import { createMarkdown, h } from 'mdlib-pure'
import { grammars, tokenize } from './highlight.js' // ~60 lines, site/lib/highlight.js

const md = createMarkdown({
  // VNodes keep renderTo() on its DOM-safe path; null means default rendering
  highlight: (code, lang) =>
    grammars.has(lang)
      ? tokenize(code, grammars.get(lang)).map(([cls, text]) => (cls ? h('span', { class: `tok-${cls}` }, text) : text))
      : null,
})
```

````markdown
```js
// A minimal highlighter: returns VNodes, not HTML
const md = createMarkdown({
  highlight: (code, lang) => (lang === 'js' ? tokens(code) : null),
})
md.render('# Hello')
```

```css
:root {
  --md-color-link: oklch(55% 0.2 260);
}
```

```sh
npm install mdlib-pure
```
````

## Tailwind classes map

Without the theme, the `classes` option gives each node type its utility classes. The preview uses a real Tailwind CSS v4 build, isolated in a shadow root.

```js
createMarkdown({
  classes: {
    heading: 'font-semibold tracking-tight',
    heading2: 'mb-3 text-2xl',
    paragraph: 'my-3 leading-7',
    link: 'font-medium text-(--md-color-link) underline decoration-2 underline-offset-4',
    inlineCode: 'rounded bg-current/10 px-1 font-mono text-sm',
    list: 'my-3 list-disc pl-6 marker:text-(--md-color-link)',
    blockquote: 'my-3 border-l-4 border-(--md-color-link) pl-4 italic',
  },
})
```

```markdown
## A heading made of utilities

Every node type gets its own classes: no theme, just **Tailwind**,
[links](https://tailwindcss.com) and `inline code` included.

- first item
- second item

> A block quote with a left border.
```

## React adapter

`mdlib-pure/adapter` turns VNodes into React, Preact or Vue elements. This preview was produced by `react-dom/server` when the site was built.

```jsx
import { createElement } from 'react'
import { createMarkdown } from 'mdlib-pure'
import { gfm } from 'mdlib-pure/gfm'
import { toElements } from 'mdlib-pure/adapter'

const md = createMarkdown({ plugins: gfm() })

export function Markdown({ source }) {
  return <article className="md">{toElements(md.toVNodes(source), createElement, 'react')}</article>
}
```

```markdown
## From Markdown to React

`toElements()` turns VNodes into React elements with `createElement`.

- [x] `className` instead of `class`
- [x] uncontrolled checkboxes (`defaultChecked`)
- [x] a `key` on top-level elements
```

## Web Components, live

`mdlib-pure/element` defines `<mdlib-markdown>` and `<mdlib-editor>`. Both are live below, defined in your browser from the HTML above: the viewer renders its `source` attribute, the editor renders its preview on every keystroke and sends a debounced `input` event. KaTeX and Mermaid come from this site, loaded only when the text needs them.

```js
import { defineElements } from 'mdlib-pure/element'

// This site's own KaTeX and Mermaid, fetched only on first use
// (simplified from site/client/elements.js)
defineElements({
  loaders: {
    katex: () => loadKatexAutoRender(), // resolves to renderMathInElement
    katexStylesheet: '/assets/katex/katex.min.css',
    mermaid: () => import('/assets/mermaid/mermaid.js'),
  },
})

// Debounced: 200 ms after the last keystroke (the delay attribute)
document.querySelector('mdlib-editor').addEventListener('input', (e) => save(e.target.value))
```

````html
<mdlib-markdown class="md" plugins="gfm math"
  source="**Rendered in your browser** from the `source` attribute,
  with GFM and math: ~~strikethrough~~, www.commonmark.org
  and $a^2 + b^2 = c^2$."></mdlib-markdown>

<mdlib-editor plugins="all" label="Sample document" style="block-size: 34rem"
  value="## Edit me

This is a real `<mdlib-editor>`: the preview renders **on every keystroke**, in your browser.
Select a word and press Ctrl+B, or use the toolbar; *Write* and *Preview* switch the view.

- [x] every plugin, with `plugins` set to `all`
- [ ] your own text

KaTeX is loaded on first use: $e^{i\pi} + 1 = 0$.

::: tip Diagrams
Mermaid loads only when a diagram appears, and a diagram is drawn again only when its source changes.
:::

```mermaid
flowchart LR
  type[You type] --> preview[Live preview]
  preview -->|input event, debounced| app[Your app]
```
"></mdlib-editor>
````

On [the HTML page](https://michelepolo.github.io/mdlib-pure/samples/#elements) this markup runs as is, defined by [`site/client/elements.js`](https://github.com/MichelePolo/mdlib-pure/blob/main/site/client/elements.js). Guides: [Web Components](docs/elements.md), [Blazor](docs/blazor.md), [Angular](docs/angular.md).
