Building a Canvas Text Block with Pretext

·


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.

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.

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.

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.

Going big

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.

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.