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.
npm install https://github.com/MichelePolo/mdlib-pure/releases/download/mdlib-pure-v0.1.1/mdlib-pure-0.1.1.tgz Not on the npm registry yet: this installs the tarball attached to the GitHub release. Other ways to install.
Markdown
Result
Try it here
The result updates as you type,
with gfm() and mark.
- CommonMark 0.31.2, 652 of 652 examples
- 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/gfmplugin (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 and Angular 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.
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
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.
<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>
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.
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')
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.
@using MdlibPure.Blazor
<MarkdownEditor @bind-Value="Body" Plugins="MarkdownPlugins.All" />
<Markdown Value="@Body" Plugins="MarkdownPlugins.Gfm" />
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.
// 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" />`
Plugins
The core does CommonMark and nothing else. Everything else is one import away: each plugin is a separate module, measured on its own, so you pay only for what you use. First-party plugins use the same API that is open to you: block rules, inline rules, delimiter runs, AST transforms and render overrides.
| Plugin | Adds | gzip |
|---|---|---|
mdlib-pure/gfm |
tables, task lists, footnotes, strikethrough, autolinks, alerts | 3.92 KB |
mdlib-pure/headings |
heading ids, permalinks, table of contents | 0.56 KB |
mdlib-pure/container |
::: container blocks |
0.81 KB |
mdlib-pure/math |
$inline$, $$display$$ and $$ blocks |
0.94 KB |
mdlib-pure/mermaid |
```mermaid diagrams, no dependency on Mermaid |
1.49 KB |
mdlib-pure/deflist |
definition lists | 1.22 KB |
mdlib-pure/mark |
==highlight== |
0.13 KB |
mdlib-pure/frontmatter |
YAML and TOML front matter | 0.57 KB |
mdlib-pure/adapter |
React, Preact and Vue elements | 0.53 KB |
mdlib-pure/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 |
the full HTML entity table, for Node, SSR and workers | 10.75 KB |
Performance
As fast as marked, faster than markdown-it, smaller than both, and as conformant as commonmark.js.
| 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.
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 lists them all.
- Start at
/llms.txt, or take everything in one file with/llms-full.txt. AGENTS.mdis 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. - To use it in an app rather than extend it, the guides are
docs/elements.mdfor the Web Components,bindings/blazor/README.mdfor Blazor andbindings/angular/README.mdfor Angular; all are inllms-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.
The start of /llms.txt
# 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