Simple height measurement
prepare() once, then layout() with maxWidth and lineHeight. Returns height (px) and lineCount — no DOM.
View snippet →The Pretext Ecosystem
@chenglou/pretext v0.0.3 Playground, font tester, chat generator, snippets & changelog — one place. Multiline text layout without touching the DOM.
npm install @chenglou/pretext @chenglou/pretext?For years, measuring text in the browser meant putting it in the DOM and reading geometry. That triggers layout reflow — work that scales poorly for virtual lists, chat, and animations.
Pretext by Cheng Lou uses canvas.measureText() to read the font engine without entering the layout tree. It
caches widths and uses arithmetic for line breaks and height — no DOM on the hot path.
Results align with browser layout for loaded fonts, with compute times suited to 60fps UIs and large batches of text.
// Triggers layout reflow
const el = document.createElement('div');
el.style.width = width + 'px';
el.textContent = text;
document.body.appendChild(el);
const height = el.offsetHeight;
document.body.removeChild(el); import { prepare, layout } from '@chenglou/pretext';
const prepared = prepare(text, '16px Inter');
const { height, lineCount } = layout(
prepared,
width,
lineHeight
); From AI chat to creative coding — fast text measurement unlocks layouts that used to be too costly.
Measure exact text heights before mounting DOM. Build masonry and virtual lists with zero layout shift.
→ 💬Compute bubble size while streaming tokens without DOM reflow — smooth chat UIs.
→ 🌊Use layoutNextLine() for variable line widths — magazine-style flows.
→ 🖼️Multiline text in Canvas with line data from Pretext — no hidden DOM nodes.
→ 📐Answer “how tall will this be?” instantly — no ResizeObserver hacks.
→ 🎮Experiments at pretext.cool — games and generative layouts powered by fast measurement.
→Install, import, and measure in a few lines.
npm install @chenglou/pretext import { prepare, layout } from '@chenglou/pretext';
const prepared = prepare('Hello, world!', '16px Inter');
const { height, lineCount } = layout(prepared, 400, 24); import { prepareWithSegments, layoutWithLines } from '@chenglou/pretext';
const prepared = prepareWithSegments(text, '16px Inter');
const { lines } = layoutWithLines(prepared, 400, 24); Copy-paste examples for common tasks. All snippets →
prepare() once, then layout() with maxWidth and lineHeight. Returns height (px) and lineCount — no DOM.
View snippet →Map many strings to heights in the main thread. Compare with a hidden DOM node to see reflow cost.
View snippet →PreparedText is immutable measurement data. Reuse the same handle for many container widths.
View snippet →Free, in-browser — no account required.
REPL with sliders, fonts, and generated code.
InteractiveCompare Pretext vs DOM across fonts.
MeasurementStyle conversations and export HTML.
GeneratorCurated patterns for real projects.
ReferenceReleases from GitHub with fallback data.
UpdatesSee the Playground or snippets for full patterns.
| Function | Use case | Returns |
|---|---|---|
prepare(text, font) | Simple measurement handle | PreparedText |
layout(prepared, width, lineH) | Height and line count | { height, lineCount } |
prepareWithSegments(text, font) | Rich / line APIs | PreparedTextWithSegments |
layoutWithLines(prepared, width, lineH) | Per-line text and width | { lines, height, lineCount } |
layoutNextLine(prepared, cursor, maxW) | Variable width per line | LayoutLine | null |
Font strings follow CSS font shorthand. Fonts must be loaded before prepare().
Pretext FAQ
Common questions about Pretext and this site.
-
-
Pretext.wiki is the community hub for the @chenglou/pretext JavaScript library — a DOM-free text layout engine created by Cheng Lou (React core team, ReasonML author, Midjourney). This site provides an interactive Playground, Font Tester, AI Chat Bubble Generator, curated code snippets, and a full changelog tracker — all free to use.
-
-
Pretext is a small TypeScript library (zero dependencies) that measures and lays out multiline text using Canvas's measureText() API instead of the DOM. Traditional DOM measurement forces a full layout reflow — the browser recomputes positions of every element on the page. Pretext bypasses this entirely: it reads character widths from the font engine once, caches them, and uses pure arithmetic for all subsequent layouts.
-
-
The four primary use cases are: (1) Virtual list / masonry layouts — measure text heights before mounting elements to avoid layout shift; (2) Streaming AI chat bubbles — compute exact bubble width for each token without DOM reflow, enabling smooth 60fps animations; (3) Text-around-shape flows — use layoutNextLine() to reflow text around arbitrary shapes line-by-line; (4) Canvas and SVG text rendering — compute line positions for pixel-perfect custom renderers without touching the DOM.
-
-
Install via npm: npm install @chenglou/pretext. It has zero dependencies and works in any modern browser that supports the Canvas API. You can also load it in the browser via a CDN as an ES module.
-
-
prepare() is the simple API for straightforward use cases — it measures text and returns a handle you pass to layout(). prepareWithSegments() is the advanced API that segments text into words, enabling line-by-line layout via layoutNextLine() — required for text-around-shape and other variable-width scenarios. For most use cases (height measurement, masonry, chat bubbles), prepare() is sufficient.
-
-
Yes. Pretext delegates to the browser's native font engine via Canvas, which means it inherits full Unicode support — including CJK characters, Arabic, Hebrew (RTL), Thai, Devanagari, and emoji. The library uses the browser's built-in text shaping for accurate measurement across scripts.
-
-
Absolutely. Pretext is pure JavaScript with no framework dependencies. It works identically in React, Vue, Svelte, Angular, or vanilla JavaScript. The typical pattern is to call prepare() outside your render cycle (e.g., in a useMemo or computed property), then call layout() synchronously whenever the container width changes.
-
-
Pretext.wiki is an independent community resource — not officially affiliated with Cheng Lou or the @chenglou/pretext repository. All code samples follow the official API documented in the GitHub repository. For official documentation and issue tracking, visit the official GitHub repo linked in the navigation.