Engineering

Reading time estimates that are honest

A '5 minute read' label hides choices about code, tables and languages without spaces. Weight each kind of content, round to honest steps, and recompute as the writer types.

6 min read

A “5 minute read” label is one of the smallest pieces of interface in an editor, and one of the easiest to get wrong. Divide the word count by 200 and the number looks precise, but it hides several choices: whether code counts, whether a table counts, whether the reader is skimming or reading closely, and whether the text is in a language that spaces its words differently. An estimate that is labelled as precise and is not erodes trust faster than no estimate at all.

Decide what counts as reading

A block of code is read more slowly than prose, and a table of numbers is scanned rather than read. A heading or a caption is read quickly. If the estimate treats all of these as ordinary words, a technical article with many samples reads as shorter than it is, and a data-heavy page reads as longer. Count prose at the base rate, count code and tables at a lower rate, and say in the help text which rule the number follows.

Code example
function readingMinutes(blocks: { kind: "prose" | "code" | "table"; words: number }[]) {
  const rate = { prose: 230, code: 90, table: 120 }; // words per minute, rough planning values
  const minutes = blocks.reduce((sum, b) => sum + b.words / rate[b.kind], 0);
  return Math.max(1, Math.round(minutes));
}

The rates are planning values, not measurements, and the sample says so by naming them. Do not present them as findings about your readers. The point of the function is that each kind of content has its own rate, so a change to one kind does not silently shift every estimate.

Counting words is not the same in every language

Western languages separate words with spaces, so a simple split on whitespace works well for English and German. Chinese, Japanese and Thai do not put spaces between words, so a split returns the whole paragraph as one word, and the estimate collapses to one minute. Use Intl.Segmenter with the word granularity to count words, and use a character-based rate for languages that write without spaces. Set the rate from the document’s langattribute, not from the reader’s browser setting.

Round to the nearest five minutes, or say “about”

“7 minute read” suggests a precision the estimate does not have. A reader who finishes in five minutes feels misled, and the writer feels blamed. Round to the nearest five minutes for articles over ten minutes, and show “under 5 minutes” for short pieces. The label is a guide to whether the piece is worth the time, and that is what the rounding should preserve.

Update the estimate with the draft, not on publish

A writer who sees the reading time frozen at zero while drafting cannot judge the length of the piece. Recompute the estimate as the text changes, but throttle it, so a large document is not counted on every keystroke. A debounce of a second is enough for the writer, and the estimate stays cheap to compute.

A short test list


RichTextEditor is a perpetual-licence JavaScript editor — one purchase, self-hosted, no metered editor loads. Download the evaluation or see how it compares.