How a Former React Core Engineer’s Pretext Library Solves a 30‑Year‑Old Browser Text Layout Problem
Front‑end developers struggle to measure text height without rendering, causing performance issues in virtual scrolling, chat bubbles, and masonry layouts, but the TypeScript‑based Pretext library bypasses the DOM, uses Canvas measureText, and delivers order‑of‑magnitude speedups while offering line‑level layout APIs.
Front‑end code often needs the height of a text block without rendering it, but the standard APIs getBoundingClientRect() and offsetHeight trigger a synchronous layout (forced reflow), making virtual scrolling, chat‑bubble sizing, and waterfall layouts costly.
Why measurement forces reflow
The browser batches DOM changes and computes layout once. Calling a measurement API forces the browser to finish all pending changes immediately, causing a full layout pass. Measuring dozens or hundreds of blocks therefore generates many forced reflows, visible as red “Layout” markers in Chrome DevTools.
Pretext: DOM‑free measurement
Pretext is a pure TypeScript library that implements its own text‑measurement and layout algorithm. It obtains glyph metrics via the Canvas measureText() API, which does not cause layout, and then performs line‑breaking and height calculations entirely in JavaScript.
Performance comparison
Preparing 500 text blocks with prepare() costs about 19 ms (one‑time cost). Each subsequent layout() call costs only 0.09 ms and does not block the main thread. Measuring the same 500 blocks with getBoundingClientRect() costs roughly 30 ms and triggers 500 forced reflows, a difference of several orders of magnitude.
import { prepare, layout } from '@chenglou/pretext'
// Step 1: one‑time preparation
const prepared = prepare('Your text here', '16px Inter')
// Step 2: compute height for a given container width
const { height, lineCount } = layout(prepared, 320, 26)Advanced line‑level APIs
layoutWithLines()returns the content and width of each line, enabling custom rendering on Canvas or SVG. walkLineRanges() provides line positions and widths without constructing strings, useful for precise multi‑line shrink‑wrap. layoutNextLine() allows per‑line width overrides, making magazine‑style text‑around‑image layouts possible without CSS Shapes.
Real‑world demos
A chat‑bubble demo contrasts CSS fit-content (which leaves excess space) with Pretext’s shrink‑wrap, eliminating visual gaps. Another demo renders a responsive multi‑column magazine layout entirely in JavaScript, achieving results comparable to professional typesetting tools.
Scenarios that benefit
Virtual lists and scrolling : Pretext can compute exact item heights before rendering, preventing jumps and flashes.
AI conversation interfaces : As tokens stream in, heights are calculated in JavaScript, avoiding per‑token reflows.
Rich‑text editors : Precise cursor positioning, selection, and line‑height prediction remain fast even for large documents.
Responsive layout pre‑calculation : Determine whether text wraps to two or three lines for different viewport widths without actual rendering.
Limitations
Pretext supports only standard text configurations: white-space values normal and pre-wrap,
word-break normal, and
overflow-wrap break-word. Non‑standard break rules may yield inaccurate results. On macOS the generic system-ui font is discouraged because its mapping varies across versions; a concrete font such as Inter or SF Pro should be specified. The library is not a full layout engine—features like CSS Shapes are unsupported, and complex bidirectional or mixed‑direction scripts may still have edge‑case bugs.
Implementation details
Pretext uses Canvas measureText() to fetch glyph metrics without triggering layout. After obtaining metrics it runs a custom line‑breaking algorithm that respects language‑specific rules: CJK characters may break anywhere, English words cannot be split, Emoji remain intact, and bidirectional text ordering is handled. The algorithm draws inspiration from pdf.js’s bidi handling and an early text‑layout project by Sebastian Markbage (React Fiber architect). The repository contains 267 commits, with 89.5 % of the code written in TypeScript, indicating extensive handling of edge cases.
Why it matters
For three decades the web assumed browsers would handle all text layout, a premise that held for static documents. Modern web apps—chat interfaces, collaborative editors, data visualizations, AI dialogs—require fine‑grained control over text layout that CSS cannot provide. Native platforms already expose measurement APIs (iOS NSAttributedString.boundingRect, Android StaticLayout), and Pretext fills this gap for the web, proving that extracting measurement from the DOM is technically feasible and yields massive performance gains, although the library is still early‑stage.
Project URL: https://github.com/chenglou/pretext
Online demo: https://chenglou.me/pretext/
Install:
npm install @chenglou/pretextSigned-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
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.
