markdown
measured markdown renderer powered by pretext. every block is measured before it hits the DOM — pure arithmetic, zero reflows.
plugins
each block type is a plugin that owns its measurement and rendering. core only handles paragraphs and headings.
headings & inline formatting
Heading 1
Heading 2
Heading 3
Regular paragraph with bold, italic, and strikethrough text. Inline code works too. Links like inference.sh are styled automatically.
Blockquotes can contain mixed formatting and work with the measurement engine — every line is measured, not estimated.
code blocks
interface MeasureStrategy { kind: 'fixed' | 'computed' height?: number measure?: (width: number) => number}// Height = lines × lineHeight + chrome// No DOM needed — pure arithmeticfunction measureCodeBlock(code: string, lineHeight = 18) { const lines = code.split('\n').length return lines * lineHeight + 67 // header + padding + border}tables
| Feature | Measured | Plugin |
|---|---|---|
| Paragraphs | pretext inline layout | core |
| Headings | pretext with font config | core |
| Code blocks | lines × lineHeight + chrome | code-block |
| Tables | rows × rowHeight + header | table |
| Blockquotes | recursive with indent | blockquote |
| Lists | recursive with indent | list |
| Images | aspect ratio, max height | image |
| YouTube | 16:9 aspect ratio | youtube |
| HR | fixed 1px | hr |
lists
Unordered:
Text measurement via pretext — pure canvas, zero DOM
Plugin system — blocks own their dimensions and rendering
Virtualizable — strategy heights feed directly into the virtualizer
Ordered with nesting:
Parse markdown (remark + remark-gfm)
Walk AST into layout IR (
BlockNode/InlineItem)Measure:
Inline: pretext
prepareWithSegments+layoutNextLineBlocks: plugins handle their own height
Render measured lines or fall back to flow mode
images & embeds
Images are zoomable — click to expand:
YouTube links auto-embed:
Horizontal rules are a 1px fixed-height plugin.
responsive
text reflows on width change. the component auto-measures its container via ResizeObserver.
Responsive reflow — drag the slider to resize. Text is re-measured via pretext on every width change. Code blocks, tables, and embeds adapt too.
// pretext measures text with canvas// zero DOM reads, zero layout thrashingconst prepared = prepareWithSegments(runs, font)let line = layoutNextLine(prepared, maxWidth)| Feature | Responsive |
|---|---|
| Text | Reflows via pretext |
| Code | Scrolls horizontally |
| Tables | Overflow scroll |
| Images | Aspect ratio preserved |
List items reflow with the container
Bold and italic text stays on the correct lines
Inline
coderespects word boundaries
virtualized
measurement strategies feed directly into a virtualizer. only visible items are in the DOM.
installation
npx shadcn@latest add https://ui.inference.sh/r/markdown.json