How Pretext Eliminates DOM Reflows for Ultra‑Fast Text Measurement
Pretext, a zero‑DOM, high‑performance text measurement engine created by React core contributor chenglou, uses Canvas‑based calculations and a two‑stage prepare/layout workflow to avoid layout reflows, delivering up to 500× speed gains for virtual scrolling, rich‑text rendering, and AI‑driven UI layout predictions.
Traditional text measurement in front‑end development renders strings into the DOM and reads dimensions via getBoundingClientRect or offsetHeight, which forces a layout reflow and causes jank when measuring thousands of items.
Pretext Library
Pretext is a pure JavaScript/TypeScript engine for text measurement and layout. It avoids DOM manipulation by using Canvas for width calculation and supports DOM, Canvas, and SVG rendering. The design is inspired by Sebastian Markbage’s text‑layout project and is planned to work in server‑side environments.
Core Implementation
DOM‑free measurement : Canvas measures text width without creating DOM nodes, eliminating reflows.
Two‑stage workflow : prepare normalizes, tokenizes and segments the text once; layout performs only arithmetic on the cached data.
Full language support : Handles CJK, RTL, Emoji and bidirectional text out of the box.
Performance Characteristics
Zero reflow : No DOM operations, so measurement count is not limited by layout cost.
Benchmark : Preparing 500 text blocks takes ~19 ms; laying them out takes ~0.09 ms, roughly 500× faster than DOM‑based methods.
Cacheable results : Layout output can be cached, providing deterministic dimensions and avoiding layout shift.
Key API Usage
Basic measurement:
import { prepare, layout } from '@chenglou/pretext';
const prepared = prepare('AGI spring is here', '16px Inter');
const { height, lineCount } = layout(prepared, 300, 20);Preserve whitespace (e.g., for textarea):
const prepared = prepare(textareaValue, '16px Inter', { whiteSpace: 'pre-wrap' });
const { height } = layout(prepared, textareaWidth, 20);Custom line‑by‑line layout:
import { prepareWithSegments, layoutNextLine } from '@chenglou/pretext';
const prepared = prepareWithSegments('Long text', '18px Helvetica Neue');
let cursor = { segmentIndex: 0, graphemeIndex: 0 };
let y = 0;
while (true) {
const width = y < image.bottom ? columnWidth - image.width : columnWidth;
const line = layoutNextLine(prepared, cursor, width);
if (!line) break;
ctx.fillText(line.text, 0, y);
cursor = line.end;
y += 26;
}Utility functions:
import { clearCache, setLocale } from '@chenglou/pretext';
clearCache(); // free memory
setLocale('zh-CN'); // set language localeInstallation & Quick Start
npm install @chenglou/pretext
# optional local demo
git clone https://github.com/chenglou/pretext
cd pretext
bun install
bun startProject repository: https://github.com/chenglou/pretext
Typical Use Cases
High‑performance virtual scrolling or infinite lists
Rich‑text and complex custom layouts
AI‑generated UI layout predictions
Cross‑Canvas/SVG rendering
Server‑side text layout calculations
Practical Recommendations
Integrate Pretext early in virtual‑scroll implementations.
Reuse the result of prepare across multiple layout passes.
Call clearCache when switching fonts or after large batches to manage memory.
Keep CSS font and line-height values in sync with the parameters passed to Pretext for accurate measurements.
AI Architecture Path
Focused on AI open-source practice, sharing AI news, tools, technologies, learning resources, and GitHub projects.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
