HTML rich text,
drawn on canvas.

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

Design editor Image generator 2D game Presentation tool Diagram builder WebGL app

Your users will want bold, italic, lists, and colors.
Don't build a text engine — use one.

HTML input
Canvas output

Paragraphs, headings, lists, inline formatting — rendered fast and consistent across browsers.

Try it live
npm i render-tag

Interactive demo

Edit the rich text below. The canvas renders identical content at the same width.

Render ms
Editor
Canvas

What it renders

Every example below is drawn live onto a canvas element.

Rich text
Decorations
Nested lists
Mixed fonts
RTL & bidi
Text alignment
Gradient text
Text shadows
Letter & word spacing
Headings & hierarchy

Performance

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.

API

render(config) → { canvas, height, layoutRoot, lines }
OptionTypeDefaultDescription
htmlstringHTML string to render
widthnumberLayout width in CSS pixels
heightnumberautoFixed height, or auto-sized from content
ctxContext2DExisting canvas context to draw onto
canvasCanvascreatedTarget canvas element
pixelRationumberdevicePixelRatioHiDPI 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.

Quick start

import { render } from 'render-tag';

const { canvas, height } = render({
  html: '<p>Hello <strong>world</strong></p>',
  width: 400,
});

document.body.appendChild(canvas);

Layout once, draw many

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 });