If you have been searching for "pretext npm," "pretext javascript," or "pretext typescript," you are in the right place. Pretext is a pure JavaScript text layout engine available on npm that computes line breaks, text height, and layout dimensions — all without touching the DOM. It is written in TypeScript with full type definitions included.
This guide covers everything you need to get started: installing the Pretext npm package, understanding the API, using it with TypeScript, integrating it with popular frameworks, and applying it to real-world use cases.
Installing Pretext from NPM
Getting started with the Pretext npm package takes one command:
npm install pretextOr with other package managers:
# yarn
yarn add pretext
# pnpm
pnpm add pretext
# bun
bun add pretextThe Pretext npm package is approximately 15KB gzipped, has zero dependencies, and includes TypeScript type definitions out of the box. There is nothing else to install and nothing to configure.
Quick Start — Your First Pretext Layout
Here is the simplest possible Pretext JavaScript example:
import { prepare } from 'pretext';
// 1. Create a measurement context for your font
const ctx = prepare({
fontFamily: 'Inter',
fontSize: 16,
lineHeight: 1.5,
});
// 2. Compute layout at a given width
const result = ctx.layout('Hello, world! This is Pretext.', {
width: 200,
});
console.log(result.height); // total height in pixels
console.log(result.lines); // number of linesThat is it. Two function calls — prepare() and layout() — and you have exact text dimensions without any DOM access.
Pretext TypeScript Support
The Pretext npm package is written in TypeScript and ships with complete type definitions. You get full autocomplete, type checking, and documentation in any TypeScript-aware editor.
import { prepare } from 'pretext';
import type { PrepareOptions, LayoutResult } from 'pretext';
const options: PrepareOptions = {
fontFamily: 'Inter',
fontSize: 16,
lineHeight: 1.5,
};
const ctx = prepare(options);
const result: LayoutResult = ctx.layout(
'Pretext TypeScript support is first-class.',
{ width: 320 }
);
// TypeScript knows the shape of LayoutResult
console.log(result.height); // number
console.log(result.lines); // numberNo need for @types/pretext or any additional type packages — everything is included in the Pretext npm package itself.
The Pretext JavaScript API
The Pretext API is small, focused, and designed around a two-phase architecture: prepare once, layout many times.
prepare(options)
Creates a reusable measurement context for a specific font configuration.
const ctx = prepare({
fontFamily: 'Inter', // CSS font-family string
fontSize: 16, // font size in pixels
lineHeight: 1.5, // line height multiplier
});This is the only function that does any "expensive" work — it analyzes font metrics and builds internal lookup tables. It runs once per font configuration and takes roughly 0.1–1ms. The returned context is reusable for unlimited layout calls.
ctx.layout(text, options)
Computes line breaks and total height for the given text at the given width.
const result = ctx.layout('Your text here', {
width: 300, // container width in pixels
});
// result.height — total height in pixels
// result.lines — number of linesEach layout() call takes approximately 0.0002ms — that is 600x faster than DOM measurement. You can call it thousands of times per frame.
ctx.layoutWithLines(text, options)
Like layout(), but also returns the text content and width of each line.
const result = ctx.layoutWithLines('Your text here', {
width: 300,
});
result.lineData.forEach((line) => {
console.log(line.text, line.width);
});Useful when you need to know exactly where each line breaks — for rendering custom text layouts, underlining specific lines, or building text editors.
ctx.layoutNextLine(text, options)
Computes one line at a time with variable width per line. This is the most powerful function in the Pretext JavaScript API — it enables text reflow around irregular shapes.
let cursor = 0;
const lineWidths = [400, 380, 350, 320, 300]; // narrowing container
lineWidths.forEach((width) => {
const line = ctx.layoutNextLine(text, { width, cursor });
console.log(line.text, line.width);
cursor = line.cursor;
});This is how the community showcases achieve text wrapping around 3D objects, umbrellas, and other irregular shapes — each line gets a different available width.
ctx.walkLineRanges(text, options, callback)
Iterates over line boundaries without building strings. The most memory-efficient way to process line breaks in the Pretext JavaScript library.
ctx.walkLineRanges('Your text here', { width: 300 }, (start, end) => {
console.log(`Line from index ${start} to ${end}`);
});clearCache()
Clears internal glyph-width caches. Useful in long-running applications where font configurations change frequently.
import { clearCache } from 'pretext';
clearCache();Using Pretext in JavaScript Projects
With React
Pretext works naturally with React. Create the measurement context once and use it across renders:
import { useMemo } from 'react';
import { prepare } from 'pretext';
function TextBlock({ text, width }) {
const ctx = useMemo(() => prepare({
fontFamily: 'Inter',
fontSize: 16,
lineHeight: 1.5,
}), []);
const { height } = ctx.layout(text, { width });
return (
<div style={{ width, height }}>
{text}
</div>
);
}This pattern is especially powerful for virtual scrolling — predict the height of every item without mounting it to the DOM.
With Vue
import { ref, computed } from 'vue';
import { prepare } from 'pretext';
const ctx = prepare({
fontFamily: 'Inter',
fontSize: 16,
lineHeight: 1.5,
});
const text = ref('Your dynamic text here');
const width = ref(300);
const height = computed(() => {
return ctx.layout(text.value, { width: width.value }).height;
});With Svelte
<script>
import { prepare } from 'pretext';
const ctx = prepare({
fontFamily: 'Inter',
fontSize: 16,
lineHeight: 1.5,
});
let text = 'Your dynamic text here';
let width = 300;
$: result = ctx.layout(text, { width });
</script>
<div style="width: {width}px; height: {result.height}px">
{text}
</div>With Node.js / Server-Side
Because Pretext has zero DOM access, it runs natively in server environments:
// Works in Node.js, Deno, Bun
import { prepare } from 'pretext';
const ctx = prepare({
fontFamily: 'Inter',
fontSize: 16,
lineHeight: 1.5,
});
// Pre-calculate layout on the server
const result = ctx.layout(articleContent, { width: 680 });
console.log(`Article height: ${result.height}px, ${result.lines} lines`);This enables server-side layout pre-calculation — send the client exact dimensions so there is zero layout shift on page load.
In Web Workers
Offload text measurement to a background thread:
// worker.js
import { prepare } from 'pretext';
const ctx = prepare({
fontFamily: 'Inter',
fontSize: 16,
lineHeight: 1.5,
});
self.onmessage = (e) => {
const { text, width } = e.data;
const result = ctx.layout(text, { width });
self.postMessage(result);
};The main thread stays completely free while Pretext computes layouts in the background.
Real-World Use Cases
Virtual Scrolling
The most common use case for the Pretext npm package. Predict row heights for thousands of items without mounting any DOM elements:
const ctx = prepare({ fontFamily: 'Inter', fontSize: 14, lineHeight: 1.5 });
const items = messages.map((msg) => ({
...msg,
estimatedHeight: ctx.layout(msg.text, { width: containerWidth }).height + padding,
}));
// Pass to React Virtuoso, TanStack Virtual, or any virtualizerChat Interfaces
Size message bubbles precisely. No more oversized bubbles with wasted whitespace:
// Find the minimum width that keeps the same line count
const fullResult = ctx.layout(message, { width: maxBubbleWidth });
let optimalWidth = maxBubbleWidth;
// Binary search for tightest fit
let lo = 100, hi = maxBubbleWidth;
while (lo < hi) {
const mid = (lo + hi) >> 1;
const test = ctx.layout(message, { width: mid });
if (test.lines === fullResult.lines) hi = mid;
else lo = mid + 1;
}
optimalWidth = lo;Responsive Layout Pre-Calculation
Compute text dimensions at multiple breakpoints from a single prepare() call:
const ctx = prepare({ fontFamily: 'Inter', fontSize: 16, lineHeight: 1.5 });
const mobile = ctx.layout(text, { width: 320 });
const tablet = ctx.layout(text, { width: 768 });
const desktop = ctx.layout(text, { width: 1024 });
// Three layouts, zero DOM operationsPretext JavaScript vs Other Approaches
| Approach | Speed | DOM Required | SSR | TypeScript | Bundle Size |
|---|---|---|---|---|---|
| Pretext npm | ~0.0002ms | No | Yes | Built-in | ~15KB |
| DOM measurement | ~0.06ms | Yes | No | N/A | N/A |
| Canvas measureText | ~0.01ms | Partial | No | N/A | N/A |
| Hidden span hack | ~0.1ms | Yes | No | N/A | N/A |
Pretext is the only JavaScript text measurement solution that works everywhere — browser, server, worker — with zero DOM access and full TypeScript support.
Community Showcases
Developers are using the Pretext npm package to build things that were previously impossible in the browser:
tldraw — Instant Canvas Text
The tldraw collaborative whiteboard uses Pretext for instant text measurement — smooth text reflow without any DOM access.
3D Object Text Wrap
Text wrapping around a 3D gaussian splat in real time, powered by Pretext's layoutNextLine() variable-width API.
Sand Writing Effect
Characters appear as if drawn in sand — precise text positioning from Pretext meets artistic Rive animation.
60FPS Playground Stress Test
Andrea Giammarchi pushed the Pretext playground from 60fps to its absolute limits — demonstrating real-time text layout at scale.
Frequently Asked Questions
Is the Pretext npm package free?
Yes. Pretext is MIT-licensed and completely free for any use — personal, commercial, or open source.
Does Pretext JavaScript work with my framework?
Yes. Pretext is framework-agnostic with zero dependencies. It works with React, Vue, Svelte, Angular, Solid, vanilla JavaScript, and any other framework.
Does the Pretext npm package include TypeScript types?
Yes. Pretext is written in TypeScript and ships complete type definitions. No @types package needed.
Can I use Pretext in Node.js / server-side?
Yes. Pretext has zero DOM access, so it runs natively in Node.js, Deno, Bun, and edge runtimes like Cloudflare Workers.
How accurate is Pretext compared to the browser?
Pretext uses the browser's own font engine (via Canvas measureText()) as ground truth during the prepare() phase. The layout() results match browser rendering with sub-pixel accuracy.
Does Pretext handle CJK, Arabic, and other scripts?
Yes. Pretext uses Intl.Segmenter for Unicode-aware word boundary detection. It handles CJK characters, Arabic, Hebrew, Thai, Korean, emoji, and mixed-script text with the same API.
Get Started
Install the Pretext npm package and start measuring text in JavaScript or TypeScript today:
npm install pretext- Try the Playground — Experiment with Pretext interactively
- Browse Demos — See 25+ community showcases
- Explore the Library — Deep dive into the architecture
- View on GitHub — Star the repo and contribute
- About Chenglou — Meet the creator



