# mdlib-pure: Markdown, to the letter

mdlib-pure renders Markdown to HTML in the browser and follows CommonMark to the letter: all 652 spec examples, in 11.04 KB gzipped, with zero dependencies.

Not on the npm registry yet: this installs the tarball attached to the [GitHub release](https://github.com/MichelePolo/mdlib-pure/releases/tag/mdlib-pure-v0.1.1). [Other ways to install](docs/getting-started.md#install).

```sh
npm install https://github.com/MichelePolo/mdlib-pure/releases/download/mdlib-pure-v0.1.1/mdlib-pure-0.1.1.tgz
```

- [Read the docs](docs/getting-started.md)
- [Open the playground](playground.md)

## Live example

```markdown
## Try it here

The result updates **as you type**,
with `gfm()` and ==mark==.

- [x] CommonMark 0.31.2, 652 of 652 examples
- [x] tables, ~~strikethrough~~, footnotes, alerts
- [ ] your plugin

> [!TIP]
> The DOM is built without parsing HTML.
```

## Datasheet

CommonMark 0.31.2
: 652 of 652 spec examples, with byte-identical output

GitHub Flavored Markdown
: 54 of 54 extension examples, in the optional `mdlib-pure/gfm` plugin (3.92 KB gzip)

Size
: 11.04 KB minified and gzipped, within a 15 KB budget checked by `npm run size`

Runtime dependencies
: none, checked by `npm run check`

Safe by default
: raw HTML not recognized, URLs filtered by an allowlist, DOM built without parsing HTML

Linear time
: on adversarial input too: 30+ hostile inputs with time limits in `test/pathological.test.ts`

Output
: an HTML string, DOM nodes, React, Preact and Vue elements through the adapter, or the `<mdlib-markdown>` and `<mdlib-editor>` Web Components, which the [Blazor](docs/blazor.md) and [Angular](docs/angular.md) wrappers build on

## Ways to use it

One parser and one renderer behind five entry points: pick the one your stack speaks. None is on a package registry yet: each guide says how to install it today.

### JavaScript

The core API: `render()` returns an HTML string, `renderTo()` builds DOM nodes without parsing HTML. Each plugin is one more import.

```js
import { createMarkdown } from 'mdlib-pure'
import { gfm } from 'mdlib-pure/gfm'

const md = createMarkdown({ plugins: gfm() })
md.render('# Hello')        // an HTML string
md.renderTo(el, '# Hello')  // DOM nodes, no HTML parsing
```

[Getting started](docs/getting-started.md) · [API reference](docs/api.md)

### HTML: Web Components

`mdlib-pure/element` defines `<mdlib-markdown>`, a viewer, and `<mdlib-editor>`, an editor with toolbar and live preview, for plain pages and any framework. Core and every plugin included: 20.19 KB gzip.

```html
<script type="module">
  // with a bundler or an import map
  import { defineElements } from 'mdlib-pure/element'
  defineElements()
</script>

<mdlib-markdown class="md" plugins="gfm"
  source="# Hello"></mdlib-markdown>
<mdlib-editor name="body" plugins="all"
  value="# Draft"></mdlib-editor>
```

[Web Components guide](docs/elements.md) · [Live sample](samples.md#elements)

### React, Preact, Vue

`mdlib-pure/adapter` turns the output into elements with the framework’s own `createElement` or `h`, following its conventions: `className`, `defaultChecked`, keys.

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

export const Markdown = ({ source }) => (
  <article className="md">
    {toElements(md.toVNodes(source), createElement, 'react')}
  </article>
)
// Vue: toElements(vnodes, h, 'vue')
// Preact: toElements(vnodes, h, 'preact')
```

[The adapter](plugins.md#adapter) · [React sample](samples.md#react)

### Blazor (.NET 10)

`MdlibPure.Blazor` 0.2.0 wraps the Web Components for every render mode (Static SSR, Server, WebAssembly, Auto): `@bind-Value`, `EditForm` validation, a C# service for the AST and a podcast editor (`PodcastEditor`). Not on nuget.org yet: the `.nupkg` is attached to the GitHub release.

```razor
@using MdlibPure.Blazor

<MarkdownEditor @bind-Value="Body" Plugins="MarkdownPlugins.All" />
<Markdown Value="@Body" Plugins="MarkdownPlugins.Gfm" />
```

[Blazor guide](docs/blazor.md) · [Download 0.2.0 from the GitHub release](https://github.com/MichelePolo/mdlib-pure/releases/tag/blazor-v0.2.0)

### Angular (21, 22)

`ngx-mdlib-pure` 0.2.0: standalone components whose tag is the Web Component, `[(value)]` with signals, a form control for `ngModel` and reactive forms, SSR with hydration, a service for the AST and a podcast editor (`ngx-mdlib-pure/podcast`). Not on npm yet, like mdlib-pure: both tarballs are attached to GitHub releases.

```ts
// app.config.ts
providers: [provideMdlibPure({ loaders: { mermaid: () => import('mermaid') } })]

// a component, imports: [MarkdownEditor, MarkdownViewer]
template: `
  <mdlib-editor [(value)]="body" plugins="all" />
  <mdlib-markdown [source]="body()" plugins="all" />`
```

[Angular guide](docs/angular.md) · [Install from the GitHub releases](docs/angular.md#install)

## Plugins

The core does CommonMark and nothing else. Everything else is one import away: each plugin is a separate module, measured on its own. [All plugins](plugins.md).

| Plugin | Adds | gzip |
|:--|:--|--:|
| [`mdlib-pure/gfm`](plugins.md#gfm) | tables, task lists, footnotes, strikethrough, autolinks, alerts | 3.92 KB |
| [`mdlib-pure/headings`](plugins.md#headings) | heading ids, permalinks, table of contents | 0.56 KB |
| [`mdlib-pure/container`](plugins.md#container) | `:::` container blocks | 0.81 KB |
| [`mdlib-pure/math`](plugins.md#math) | `$inline$`, `$$display$$` and `$$` blocks | 0.94 KB |
| [`mdlib-pure/mermaid`](plugins.md#mermaid) | ` ```mermaid ` diagrams, no dependency on Mermaid | 1.49 KB |
| [`mdlib-pure/deflist`](plugins.md#deflist) | definition lists | 1.22 KB |
| [`mdlib-pure/mark`](plugins.md#mark) | `==highlight==` | 0.13 KB |
| [`mdlib-pure/frontmatter`](plugins.md#frontmatter) | YAML and TOML front matter | 0.57 KB |
| [`mdlib-pure/adapter`](plugins.md#adapter) | React, Preact and Vue elements | 0.53 KB |
| [`mdlib-pure/element`](plugins.md#element) | the `<mdlib-markdown>` viewer and the `<mdlib-editor>` editor with live preview, as Web Components (core and every plugin included) | 20.19 KB |
| [`mdlib-pure/entities`](plugins.md#entities) | the full HTML entity table, for Node, SSR and workers | 10.75 KB |

## Performance

| Library | CommonMark examples (exact) | spec.txt MB/s | README MB/s | min + gzip |
|:--|--:|--:|--:|--:|
| **mdlib-pure** | **652/652** | 43.5 | 36.4 | **10.9 KB** |
| marked | 503/652 | 44.6 | 32.7 | 14.0 KB |
| markdown-it | 649/652 | 35.6 | 22.0 | 40.6 KB |
| commonmark.js | 652/652 | 47.4 | 48.2 | 46.8 KB |

Node 22.22.1, render to an HTML string, median of 15 runs, measured on 28 October 2026; differences under about 10% are noise. With GFM: mdlib-pure + gfm() 39.6 / 25.1 MB/s, marked 38.8 / 27.2 MB/s, markdown-it 28.7 / 17.4 MB/s; mdlib-pure also does footnotes, task lists and alerts. [Full method and results](https://github.com/MichelePolo/mdlib-pure/blob/main/bench/RESULTS.md).

## For AI agents

This site reads fine without a browser. Every page has a Markdown version at the same address with `.md`, and [`/llms.txt`](llms.txt) lists them all.

- Start at [`/llms.txt`](llms.txt), or take everything in one file with [`/llms-full.txt`](llms-full.txt).
- [`AGENTS.md`](docs/extending.md) is the extension contract: rules checked by commands, recipes for each extension point, a definition of done.
- To get a plugin from an agent: “Read AGENTS.md and write a plugin that…”, then let it run `npm run verify`. Example prompts are in the [guide for agents](docs/agents.md).
- To use it in an app rather than extend it, the guides are [`docs/elements.md`](docs/elements.md) for the Web Components, [`bindings/blazor/README.md`](docs/blazor.md) for Blazor and [`bindings/angular/README.md`](docs/angular.md) for Angular; all are in `llms-full.txt`.
- Nothing is on a registry yet: no `npm install mdlib-pure`, no NuGet package. Each guide's Install section says what works today.

```markdown
# mdlib-pure

> Lightweight, zero-dependency Markdown renderer for the browser: 100% CommonMark 0.31.2 (652/652 spec examples), GitHub Flavored Markdown as an opt-in plugin (54/54 extension examples), an ~11 KB gzipped core, safe by default, linear time on any input. Extensible through plugins, styled with semantic CSS tokens, output as HTML, DOM, React/Preact/Vue elements, or the <mdlib-markdown> and <mdlib-editor> Web Components, which the MdlibPure.Blazor (.NET 10) and ngx-mdlib-pure (Angular) wrappers build on. Not on a package registry yet (no npm, no NuGet): the Install section of each guide says how to install it today.

Every page of this site has a Markdown version at the same path with `.md`; the docs are the repository's own Markdown files. To extend the library, read AGENTS.md ("Extending: plugin guide") fully first: it is the contract for AI agents, and `npm run verify` must pass before a task is done. To use it in a page or an app, the guides are docs/elements.md (Web Components), bindings/blazor/README.md (Blazor) and bindings/angular/README.md (Angular). Nothing is published on npm or NuGet yet: never suggest `npm install mdlib-pure`; README.md (Install) gives the tarball URL on the GitHub release.

## Docs

- [Getting started](https://michelepolo.github.io/mdlib-pure/docs/getting-started.md): install, usage, options, highlighting, frameworks, styling, plugins, performance
```
