Word & Character Counter
Count words, characters, sentences, paragraphs, and estimate reading/speaking time.

Utilities

Word & Character Counter

Count words, characters, sentences, paragraphs, and estimate reading/speaking time.

The Word & Character Counter measures seven stats live as you type: Words, Characters, Characters (no spaces), Sentences, Paragraphs, Reading Time (~200wpm), and Speaking Time (~150wpm) — each on its own card with a descriptive emoji. The StepIndicator walks Input → Results, but the stats grid actually updates on every keystroke via countStats dispatched into Redux, so you are never stuck waiting on a second step for the numbers.

Share encodes your text into a URL hash (copyShareableUrl / decodeToolConfig) rather than posting it to a server — the toast says "Link copied!" and reopening that link restores the full text on mount. Clear resets everything with a "Cleared!" toast. Empty input returns all zeros and "0 min" times, so a fresh page reads cleanly. The card describes the job plainly: "Count words, characters, sentences, paragraphs, and estimate reading/speaking time."

How it works

lib/wordCounter.ts countStats computes characters as the raw length, no-spaces by stripping \s, words via trim().split(/\s+/).filter(Boolean), sentences by splitting on [.!?]+ and keeping non-empty pieces, and paragraphs by splitting on blank lines (\n\s*\n) with a fallback of 1 when any text is present. Reading time is words/200 minutes and speaking time words/150 minutes, each rounded up with a "< 1 min" special case.

The wordCounterSlice holds text and result; an effect dispatches resultSet on every text change so the seven cards stay in lockstep with the textarea. Share builds a client-side URL hash containing your config and, on mount, decodeToolConfig('word-counter') dispatches textSet to restore it — no API server is involved in either direction. Stats recompute fully in the browser.

How to use

  1. On Step 1 "Input", paste or type into "Input Text" (placeholder "Type or paste your text here...").
  2. Watch the stats grid update live on every keystroke (countStats → resultSet).
  3. Read the seven cards: Words, Characters, Characters (no spaces), Sentences, Paragraphs, Reading Time (~200wpm), Speaking Time (~150wpm).
  4. Click "Share" to copy a URL hash containing your text — toast "Link copied!" (or "Failed to copy link" on denial).
  5. Reopen a shared link — the text restores on mount via decodeToolConfig('word-counter').
  6. Click "Clear" to reset state (toast "Cleared!") and return the flow to Step 1 "Input".

Tips

  • Reading time assumes 200 words per minute and speaking 150 wpm — both rates are printed right on the card labels.
  • Empty text returns all zeros and "0 min" times from countStats, so clearing gives an honest baseline.
  • Paragraphs require a blank line between blocks (\n\s*\n) — a single unbroken block counts as exactly 1 paragraph.
  • Share is a URL hash, not an upload — anyone you send the link to can decode the same text client-side, so share accordingly.

Word & Character Counter FAQ

How is reading time computed?

words / 200 minutes, rounded up, with "< 1 min" shown under a minute (lib/wordCounter.ts).

What counts as a sentence?

Text split on [.!?]+ with non-empty pieces counted — each punctuation run ends a sentence.

Does Share upload my text?

No server call — copyShareableUrl encodes the config into the URL hash, and the toast "Link copied!" confirms the clipboard copy.

Can I restore from a link?

Yes — a mount effect reads decodeToolConfig('word-counter') from the hash and dispatches textSet to refill the input.

Credits

  • In-repo countStats — All counting logic in lib/wordCounter.ts; share via src/lib/shareableUrl.ts (client-side hash)
ShareTweet
More Utilities

Command Palette

Search for a command to run...