I recently came across Pretext, a JavaScript library by Cheng Lou that handles text measurement and layout without touching the DOM. No getBoundingClientRect, no layout reflow. It measures text using the browser’s canvas font engine and does all the line-breaking math itself.
I wanted to see what it could actually do, so I built a custom WordPress block that renders text on a <canvas> using Pretext for the layout. Here’s what I ended up with.
Balanced gradient headings
The first thing I tried was balanced text, where every line ends up roughly the same length instead of having one short orphan line at the end. Pretext’s walkLineRanges() makes this surprisingly easy. You binary-search for the narrowest container width that still produces the same number of lines, and you get evenly distributed text.
Build something remarkable. Ship code that matters.
That’s a <canvas> element. The gradient is a standard createLinearGradient fill, and the text gets measured once with prepareWithSegments(). Finding the balanced width takes about 20 iterations of walkLineRanges(), each one pure arithmetic with no DOM involved.
Adding glow for emphasis
Same balanced layout, but with canvas shadowBlur to add a soft bloom around the text.
The future of text on the web is here. No DOM reflow, just pure arithmetic.
Newspaper-style columns
Pretext has a layoutNextLine() API that works like an iterator. You give it a cursor position and a max width, and it returns one line. Call it in a loop and you can flow text into columns.
Pretext is a pure JavaScript library for multiline text measurement and layout. It sidesteps the need for DOM measurements like getBoundingClientRect and offsetHeight, which trigger layout reflow, one of the most expensive operations in the browser. Instead, it implements its own text measurement logic using the browser font engine as ground truth. The prepare function does one-time work: normalize whitespace, segment the text, apply glue rules, measure segments with canvas, and return an opaque handle. The layout function is the cheap hot path: pure arithmetic over cached widths. On the current benchmark, prepare takes about 19ms for a 500-text batch, while layout takes just 0.09ms for that same batch.
Text flowing around shapes
With layoutNextLine(), you can pass a different max width for each row. So I calculate where a circle intersects each line, subtract that from the available width, and let Pretext handle the line-breaking.
This text flows around a circular obstacle in the top-right corner. Each line is laid out individually using Pretext's layoutNextLine API with a different maximum width based on where the circle intersects that line. The circle chord calculation determines available space per row. Lines near the circle are shorter, lines below it stretch to full width. This kind of layout, text flowing around arbitrary shapes, has been notoriously difficult on the web. CSS Shapes exists but is limited to floats. With Pretext, you get per-line width control rendered directly to canvas.
Going big
Hello, World.
96px bold with glow. The canvas renders at devicePixelRatio so it stays crisp on retina displays.
Text flowing around an image
This is the feature CSS can’t do. The image is centered, and text flows on both sides of it. For each row, layoutNextLine() is called twice: once for the left segment, once for the right. The text reads naturally left-to-right across both sides.
The silhouette of this astronaut demonstrates text flowing on both sides of a centered image. For each row that overlaps the image, Pretext's layoutNextLine is called twice. First for the left zone, then for the right zone. The cursor advances naturally through the text. Lines above and below the image stretch to full width. Lines beside it split into two segments. This is something CSS shape-outside cannot do for centered elements. With Pretext, every line gets its own available width based on the obstacle position. The result is a magazine-style editorial layout rendered directly to canvas.
How it’s built
Everything runs as a custom WordPress block inside a mu-plugin. Pretext is bundled via 10up-toolkit, the editor uses JSX with RichText for inline editing, and the view scripts only load on pages that actually use the block. Each block lives in its own directory with its own JS, CSS, and block.json.
The tradeoff is that you lose text selection and native browser find-in-page since it’s rendered on canvas. For headings and decorative text that’s fine, but you wouldn’t want to use this for body copy you expect people to copy-paste. A hidden screen-reader-text element keeps it accessible.
If you’re building anything that needs text dimensions before rendering (virtualised lists, canvas UIs, custom layout engines), give Pretext a look. It handles edge cases I wouldn’t have thought of, like emoji measurement differences across browsers, mixed bidi text, and CJK line-breaking.
