<!-- mobian-agent-page publisher="dailydev" canonical="https://daily.dev/posts/making-the-web-fun-again-ulay1otj9" -->

---
title: Making The Web Fun Again | daily.dev
description: An introduction to pretext, a TypeScript library for fast, DOM-free text measurement and layout. The video explains why DOM-based text measurement causes...
canonical: https://daily.dev/posts/making-the-web-fun-again-ulay1otj9
twitter:card: summary_large_image
twitter:site: @dailydotdev
og:type: website
og:site_name: daily.dev
og:title: Making The Web Fun Again | daily.dev
og:description: An introduction to pretext, a TypeScript library for fast, DOM-free text measurement and layout. The video explains why DOM-based text measurement causes...
og:url: https://daily.dev/posts/making-the-web-fun-again-ulay1otj9
og:image: https://api.daily.dev/og/posts/uLaY1otJ9.png
og:image:alt: Making The Web Fun Again
og:image:width: 1200
og:image:height: 630
og:locale: en
---

> ## Documentation Index
> Fetch the complete documentation index at: https://daily.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Making The Web Fun Again

**[Joy of Code](https://daily.dev/sources/joyofcode)** · 21 min read · 4 upvotes · 0 comments

## Summary

An introduction to pretext, a TypeScript library for fast, DOM-free text measurement and layout. The video explains why DOM-based text measurement causes forced reflows and jank, then shows how pretext solves this using canvas under the hood while handling complex cases like emoji normalization, Unicode surrogate pairs, and multi-language support. Practical examples include virtualized lists with variable row heights, manual line layout rendered to DOM/SVG/canvas/Three.js, and text flowing around arbitrary obstacles — all at sub-10ms speeds. The API walkthrough covers prepare, layout, prepareWithSegments, layoutWithLines, measureLineStats, and layoutNextLineRange.

## Full article

daily.dev links to this article rather than hosting it. Read it at the original source: <https://www.youtube.com/watch?v=Em6gzss5zu0>

## Questions this post answers

### What causes forced reflow (layout thrashing) in the browser and how do I avoid it when measuring 10,000 DOM elements?

Forced reflow happens when you write to the DOM (like appending an element) and then immediately read a layout property (like offsetHeight), forcing the browser to recalculate layout synchronously. Batching all DOM writes together before doing all reads reduces some overhead, but with thousands of elements it still causes jank; measuring text off the DOM entirely, such as with Canvas or a library like pretext, avoids the problem altogether.

_Developers chasing smooth 60fps rendering can find these performance patterns curated on daily.dev._

### How can I measure text width and layout without touching the DOM in JavaScript?

Text can be measured off-DOM using the Canvas 2D context's measureText method, which returns width for a given string and font without triggering layout or reflow. The tradeoff is that you then have to implement your own line wrapping, multi-language support, and emoji/grapheme segmentation logic yourself. The pretext library builds on this canvas-based approach and handles segmentation and line wrapping internally, measuring layouts in under 10 milliseconds even for large text sets.

_Anyone optimizing text-heavy UI performance can track techniques like this via daily.dev._

### Why does a pirate flag emoji have a JavaScript string length of 5 but a spread length of 4?

A pirate flag emoji is a zero-width-join sequence made of a black flag surrogate pair (which doesn't fit in 16 bits and splits into two code units), a zero-width joiner character, the skull and crossbones code point, and a variation selector controlling rendering style, totaling 9 UTF-16 code units. JavaScript's length property counts 16-bit code units rather than visual characters, so spreading the string (which iterates by code points) gives a different count than length does.

_Developers handling emoji and Unicode edge cases in text rendering can follow deep dives like this on daily.dev._

## Similar posts on daily.dev

- [Pretext.js Bypasses DOM Layout Reflow, Enabling Advanced UX Patterns at 120 FPS](https://daily.dev/posts/pretext-js-bypasses-dom-layout-reflow-enabling-advanced-ux-patterns-at-120-fps-b1lmzt2mp) · InfoQ · 13 upvotes · 0 comments
- [Pretext and Donald Knuth](https://daily.dev/posts/pretext-and-donald-knuth-uwrj8vrwc) · Biilmann Blog · 0 upvotes · 0 comments

---

Tags: [#typescript](https://daily.dev/tags/typescript)

[View this post on daily.dev](https://daily.dev/posts/making-the-web-fun-again-ulay1otj9)

```json
{"@context":"https://schema.org","@graph":[{"@type":"Organization","@id":"https://daily.dev/#organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180},"sameAs":["https://twitter.com/dailydotdev","https://github.com/dailydotdev","https://www.linkedin.com/company/daily-dev-ltd"]},{"@type":"WebSite","@id":"https://daily.dev/#website","url":"https://daily.dev","name":"daily.dev","publisher":{"@id":"https://daily.dev/#organization"},"potentialAction":{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https://daily.dev/search?q={search_term_string}"},"query-input":"required name=search_term_string"}}]}
{"@context":"https://schema.org","@type":"TechArticle","headline":"Making The Web Fun Again","url":"https://daily.dev/posts/making-the-web-fun-again-ulay1otj9","mainEntityOfPage":{"@type":"WebPage","@id":"https://daily.dev/posts/making-the-web-fun-again-ulay1otj9"},"datePublished":"2026-07-24T16:04:22.042Z","dateModified":"2026-09-14T06:40:03.076Z","description":"An introduction to pretext, a TypeScript library for fast, DOM-free text measurement and layout. The video explains why DOM-based text measurement causes...","image":"https://i.ytimg.com/vi/Em6gzss5zu0/sddefault.jpg","thumbnailUrl":"https://i.ytimg.com/vi/Em6gzss5zu0/sddefault.jpg","isAccessibleForFree":true,"articleSection":"Joy of Code","inLanguage":"en","publisher":{"@type":"Organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180}},"author":{"@type":"Organization","name":"Joy of Code","logo":"https://media.daily.dev/image/upload/s--_wpnboLQ--/f_auto/v1726499659/logos/joyofcode","url":"https://daily.dev/sources/joyofcode"},"commentCount":0,"discussionUrl":"https://daily.dev/posts/making-the-web-fun-again-ulay1otj9","interactionStatistic":[{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":4},{"@type":"InteractionCounter","interactionType":{"@type":"CommentAction"},"userInteractionCount":0}],"keywords":"typescript","timeRequired":"PT21M","video":{"@type":"VideoObject","name":"Making The Web Fun Again","description":"An introduction to pretext, a TypeScript library for fast, DOM-free text measurement and layout. The video explains why DOM-based text measurement causes...","thumbnailUrl":"https://i.ytimg.com/vi/Em6gzss5zu0/sddefault.jpg","uploadDate":"2026-07-24T16:04:22.042Z","duration":"PT21M","url":"https://api.daily.dev/r/uLaY1otJ9","embedUrl":"https://www.youtube.com/embed/Em6gzss5zu0"}}
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://daily.dev"},{"@type":"ListItem","position":2,"name":"Joy of Code","item":"https://daily.dev/sources/joyofcode"},{"@type":"ListItem","position":3,"name":"Making The Web Fun Again"}]}
{"@context":"https://schema.org","@type":"FAQPage","@id":"https://daily.dev/posts/making-the-web-fun-again-ulay1otj9#faq","mainEntity":[{"@type":"Question","name":"What causes forced reflow (layout thrashing) in the browser and how do I avoid it when measuring 10,000 DOM elements?","acceptedAnswer":{"@type":"Answer","text":"Forced reflow happens when you write to the DOM (like appending an element) and then immediately read a layout property (like offsetHeight), forcing the browser to recalculate layout synchronously. Batching all DOM writes together before doing all reads reduces some overhead, but with thousands of elements it still causes jank; measuring text off the DOM entirely, such as with Canvas or a library like pretext, avoids the problem altogether. Developers chasing smooth 60fps rendering can find these performance patterns curated on daily.dev."}},{"@type":"Question","name":"How can I measure text width and layout without touching the DOM in JavaScript?","acceptedAnswer":{"@type":"Answer","text":"Text can be measured off-DOM using the Canvas 2D context's measureText method, which returns width for a given string and font without triggering layout or reflow. The tradeoff is that you then have to implement your own line wrapping, multi-language support, and emoji/grapheme segmentation logic yourself. The pretext library builds on this canvas-based approach and handles segmentation and line wrapping internally, measuring layouts in under 10 milliseconds even for large text sets. Anyone optimizing text-heavy UI performance can track techniques like this via daily.dev."}},{"@type":"Question","name":"Why does a pirate flag emoji have a JavaScript string length of 5 but a spread length of 4?","acceptedAnswer":{"@type":"Answer","text":"A pirate flag emoji is a zero-width-join sequence made of a black flag surrogate pair (which doesn't fit in 16 bits and splits into two code units), a zero-width joiner character, the skull and crossbones code point, and a variation selector controlling rendering style, totaling 9 UTF-16 code units. JavaScript's length property counts 16-bit code units rather than visual characters, so spreading the string (which iterates by code points) gives a different count than length does. Developers handling emoji and Unicode edge cases in text rendering can follow deep dives like this on daily.dev."}}]}
```

