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.
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
- Count a 1,000-word English article with two code samples. The estimate should be lower than the plain word count gives.
- Count a 500-character Japanese paragraph. The estimate should be above one minute, not rounded to one.
- Check that a 4-minute article is shown as under 5 minutes, not as 4 minutes.
- Type in a long draft and confirm the estimate updates within a second without the typing lagging.
- Change the document language from English to Japanese and confirm the estimate uses the new rule.
RichTextEditor is a perpetual-licence JavaScript editor — one purchase, self-hosted, no metered editor loads. Download the evaluation or see how it compares.