Spell checker documentation: word list, rules and suggestion ranking

Under the hood · Published 2026-09-03

Everything the Letterbench spell checker does, in the order it does it, with the trade-offs behind each choice.

Overview

The checker is a single JavaScript file of about two hundred lines and two plain-text word lists. There is no server component. When you press Check spelling, the script downloads the selected list (once per visit), splits your text into words, looks each word up, and wraps unknown words in a clickable element. Clicking one computes suggestions on the spot.

That design has three consequences worth stating up front: your text is never transmitted; the checker works offline once the list is loaded; and it can only be as good as a list lookup plus edit-distance suggestions, which is very good for typing errors and blind to errors that produce other real words.

The word lists

Both lists are generated from SCOWL (Spell Checking Oriented Word Lists), maintained by Kevin Atkinson and used as the basis of the English dictionaries for GNU Aspell and Hunspell. SCOWL is divided into numbered size levels, roughly from most to least common words: 10, 20, 35, 40, 50, 55, 60, 70, 80 and 95. Its README calls 35 the small size, 50 the medium and 70 the large, recommends size 60 for spell checking, and warns that sizes 80 and above are not reasonable for the purpose because they are full of rare words that mostly serve to hide misspellings.

Letterbench uses levels 10 to 50, one notch below that recommendation to keep the file small, which gives about 72,400 entries for American English and 72,300 for British English. For each variant we merged SCOWL's common English list with the variant-specific one (for example color and center for American, colour and centre for British), plus the upper-case words (names of people, places, days and months), contractions and common abbreviations at those levels. Possessive forms ending in 's were removed from the file, because the script handles them by rule; this keeps the download to about 650 KB before compression.

The file format is deliberately simple: one word per line, grouped under headers such as #10 and #35 that record the SCOWL level each group comes from. The script uses those levels as a frequency signal when ranking suggestions. The SCOWL licence permits use, modification and redistribution provided its copyright notice is kept; it is published alongside the lists in SCOWL-COPYRIGHT.txt.

Tokenizing: what counts as a word

The text is scanned with a Unicode-aware regular expression that matches runs of letters, optionally joined by an apostrophe: /[\p{L}]+(?:['’][\p{L}]+)*/gu. That keeps don't, o'clock and café in one piece and treats hyphenated compounds such as well-known as two words, which matches how SCOWL lists them. Curly apostrophes are normalized to straight ones before lookup.

Before checking, the script marks spans it will never flag:

Matching rules

A word is accepted if any of these is true:

  1. It appears in the list exactly as written. This is how names work: Paris is in the list with a capital, so Paris passes and paris does not.
  2. It is capitalized only on its first letter and its lower-case form is in the list. This covers the first word of a sentence.
  3. It is written in all capitals and its lower-case or capitalized form is in the list, so a shouted HELLO or a heading in capitals is fine.
  4. It ends in 's or s' and the word without that ending passes these rules.
  5. You added it to your own words, or chose Ignore for it during this visit.

There is no stemming beyond the possessive rule. SCOWL already lists inflected forms (walks, walked, walking) as separate entries, so stemming would add complexity and create false acceptances such as runned.

Generating suggestions

Suggestions use the edit-distance approach described by Peter Norvig in his essay How to Write a Spelling Corrector. For an unknown word of length n, the script builds every string that is one edit away:

For an eight-letter word that is a little over 450 strings, of which typically only a handful are real words. If fewer than three real words come out, the script applies the same operation to every string from the first round, which reaches words two edits away. That second round is where the cost lies: about 200,000 candidate strings for an eight-letter word. Because each check is a single lookup in a JavaScript Set, it still completes in a fraction of a second on a typical laptop or phone, and it only runs for the one word you clicked. Words of sixteen letters or more skip the second round.

The transposition rule matters more than it looks. Fred Damerau's 1964 study of spelling errors, "A technique for computer detection and correction of spelling errors", found that the large majority of the errors he examined (a figure usually quoted as over 80 percent) involved exactly one insertion, deletion, substitution or transposition of adjacent letters. Plain Levenshtein distance counts a swap as two substitutions; counting it as one is what makes recieve a distance-1 neighbour of receive. The article on Levenshtein and Damerau distance covers the difference with code.

Ranking suggestions

Candidates are sorted by these keys, in order, and the top seven are shown:

  1. Edit distance: one-edit candidates before two-edit candidates.
  2. SCOWL level: words from level 10 (the most common) before words from level 50. This is a coarse but honest frequency signal: for speling, the common spelling outranks rarer one-edit neighbours.
  3. Same first letter: people rarely get the first letter wrong, so candidates that keep it rank higher.
  4. Similar length, then alphabetical order as a final tie-breaker.

Finally, each suggestion is given the case pattern of the word you typed (Recieve → Receive, RECIEVE → RECEIVE), unless the list only knows it as a name, in which case the dictionary's capitalization is used.

Known limitations

Building your own

The page markup is a textarea, a button, a results element and a status line inside a container with an id; the script looks for those elements and wires them up. To build a checker of your own on the same principles you need three things: a word list whose licence allows redistribution (SCOWL is a good choice), a tokenizer like the regular expression above, and the edit-generation function, which is about fifteen lines. Our article on how spell checkers work compares this approach with Hunspell's affix files and the faster "symmetric delete" method, which are the next steps if you need more languages or larger dictionaries. Always set spellcheck="false" on the textarea, as this page does, so the browser's own checker does not draw a second set of underlines.