reading-time

Fast, dependency-free JavaScript library that estimates reading time from plain text, Markdown, or HTML.

Library
npm
v1.5.0
1,429stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
38/100Needs Attention
Development Activity0
Maintenance20
Community44
Maturity60
Momentum28

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
67/100Good
Architecture80
Code Quality78
Innovation75
Learning Curve35

reading-time is a lightweight, zero-dependency TypeScript library that estimates how long it will take an average person to read a piece of text, mirroring the reading-time estimate popularized by Medium. It counts words directly from a string and converts that count into a minutes/milliseconds estimate using a configurable words-per-minute baseline, working reasonably well across plain text, Markdown source, and raw HTML without needing a separate parser.

Beyond the core readingTime() function, the library exports a ReadingTimeStream Transform stream for computing a word count incrementally over large files without loading them fully into memory, plus lower-level countWords() and readingTimeWithCount() helpers for callers who want to split counting and time calculation. It also includes explicit word-boundary handling for CJK scripts (Hiragana, CJK Unified Ideographs, Hangul), a detail most naive word-counters miss.

What You Get

  • Zero-dependency readingTime(text, options) function returning minutes, milliseconds, and word count
  • Standalone countWords() and readingTimeWithCount() helpers for building custom counting pipelines
  • ReadingTimeStream Node.js Transform stream for counting words across large files without buffering them in memory
  • Built-in CJK-aware word boundary detection (Hiragana, CJK Unified Ideographs, Hangul) alongside standard whitespace-based counting
  • Full TypeScript type definitions shipped with the package

Common Use Cases

  • Blog and CMS platforms showing an “X min read” badge next to each article
  • Static site generators computing reading time at build time for Markdown content
  • Documentation sites estimating time-to-read for long-form docs pages
  • Content pipelines streaming very large text files through ReadingTimeStream to avoid loading them fully into memory

Under The Hood

Architecture The package is organized into three small, single-purpose modules: src/reading-time.ts holds the pure word-counting algorithm and time-conversion math, src/stream.ts wraps that same counting logic in a Node.js Transform stream (ReadingTimeStream) for incremental processing, and src/index.ts unifies both under a single entry point while shimming module.exports so the package works with both require('reading-time') and ESM-style default imports. There is no internal dependency injection or layering beyond this — the whole library is a thin, composable set of pure functions plus one stateful stream class, so the entry point is also effectively the full public API surface.

Tech Stack Written entirely in TypeScript with zero runtime dependencies, compiled via tsc (see tsconfig-build.json) into a CommonJS dist/ output for Node and a separate browser-facing bundle referenced by the browser field in package.json. The devDependency set is limited to typing and tooling: @types/* packages, typescript, eslint with @typescript-eslint, and mocha/ts-mocha/chai for tests. CI runs on GitHub Actions against multiple Node versions (12 and 14 per the checked-in workflow), executing npm run build followed by npm test.

Code Quality Tests live under test/ (reading-time.spec.ts, stream.spec.ts) and use mocha with chai assertions, covering both plain-English word counting edge cases (leading/trailing whitespace, links, single-character input, empty strings) and a dedicated suite of CJK scenarios (Japanese, Korean, mixed Latin/CJK text, Katakana handling). ESLint is configured with the @typescript-eslint/recommended ruleset plus a custom shared config, and the public API is fully typed through src/types.ts. Naming is consistent and functions are small and pure, which keeps the test surface manageable despite the lack of a dedicated CONTRIBUTING guide.

API Design The public API is deliberately minimal: a single default-exported readingTime(text, options) call covers the common case with a sane 200-words-per-minute default, while countWords() and readingTimeWithCount() are exposed separately for callers who need to split counting from time calculation (e.g. to aggregate counts across chunks before computing a final time). An optional wordBound function lets callers override what counts as a word boundary, and the CJK-aware detection (explicit Unicode ranges for Hiragana, CJK ideographs, and Hangul) is handled internally so most consumers never need to think about it. The ReadingTimeStream class extends Node’s Transform in object mode, giving the same counting logic a streaming interface with almost no additional API surface to learn.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search