render-tag takes HTML + CSS and draws it onto a canvas element with the 2D API. No SVG. No foreignObject. Synchronous. Zero dependencies.
For developers building
Your users will want bold, italic, lists, and colors.
Don't build a text engine — use one.
Paragraphs, headings, lists, inline formatting — rendered fast and consistent across browsers.
npm i render-tag
Edit the rich text below. The canvas renders identical content at the same width.
Every example below is drawn live onto a canvas element.
Live benchmark in your browser. Median of 3 runs. Each run takes the median of multiple iterations.
Results from MacBook Pro, Chrome.
Log scale. Other libraries use SVG foreignObject or DOM cloning — they render all HTML via the browser's own engine. render-tag is a pure Canvas 2D renderer (no SVG, no DOM snapshot) that only handles rich text. Carota is the closest canvas-based alternative.
render(config) → { canvas, height, layoutRoot, lines }| Option | Type | Default | Description |
|---|---|---|---|
html | string | — | HTML string to render |
width | number | — | Layout width in CSS pixels |
height | number | auto | Fixed height, or auto-sized from content |
ctx | Context2D | — | Existing canvas context to draw onto |
canvas | Canvas | created | Target canvas element |
pixelRatio | number | devicePixelRatio | HiDPI scaling factor |
accuracy | 'balanced' | 'performance' | 'balanced' | DOM probes for line height accuracy |
Synchronous. Fonts must be loaded before calling — use document.fonts.load() or document.fonts.ready. Re-render when fonts load if needed.
import { render } from 'render-tag';
const { canvas, height } = render({
html: '<p>Hello <strong>world</strong></p>',
width: 400,
});
document.body.appendChild(canvas);
Split layout and rendering to draw the same content onto multiple targets:
import { layout, drawLayout } from 'render-tag';
// Layout once
const { layoutRoot, height, lines } = layout({
html: '<p>Hello <strong>world</strong></p>',
width: 400,
});
// Draw to multiple canvases
const { canvas: canvas1 } = drawLayout({ layoutRoot, width: 400, height });
const { canvas: canvas2 } = drawLayout({ layoutRoot, width: 400, height });