Typing Speed Test WPM Counter — HTML CSS JS Snippet

Typing Speed Test (WPM Counter) · Forms · Plain HTML, CSS & JS · Live preview

Share & Support

What's included

Features

Live per-character diffing: target sentence re-renders with char-correct/char-incorrect spans on every input event
Standard WPM formula: (typed.length / 5) / (elapsedSeconds / 60), matching industry-standard typing test conventions
Timer starts precisely on first keystroke via a null startTime check, not on component mount
Live accuracy percentage recalculated from correct-character count divided by total characters typed so far
Extra-character handling: text typed beyond the target length is flagged separately with char-extra styling
Exact-match completion check prevents finishing the test while an uncorrected typo remains
Results overlay summarizing final WPM, accuracy, and elapsed time with a scale/opacity reveal transition
Random sample rotation from a five-sentence pool, reselected on every Try Again reset

About this UI Snippet

Typing Speed Test WPM Counter — Live Character Diffing, Words-Per-Minute Calculation & Accuracy Scoring

Screenshot of the Typing Speed Test (WPM Counter) snippet rendered live

Typing speed tests are a deceptively small feature that requires getting several interconnected pieces of logic right at once: character-by-character comparison against a target string, a words-per-minute formula that only starts counting from the user's first keystroke, an accuracy percentage that updates live, and a completion check that triggers the moment the typed text exactly matches the target. This snippet implements all of it in vanilla JavaScript with no dependencies, using the same core technique that speed-typing sites like MonkeyType and 10FastFingers rely on: comparing two strings index by index and re-rendering the sample text with per-character CSS classes on every keystroke.

Character-by-character diffing

The heart of the snippet is renderTarget(typed), which loops over every character of the target sentence and compares it against the corresponding character the user has typed so far. Each target character is wrapped in its own <span> and assigned one of three classes: char-correct (green) if typed[i] === target[i], char-incorrect (red background) if the user typed something different at that position, or no class at all if the user has not reached that character yet — except for the very next character, which gets char-current to show a blinking-style underline cursor indicator. If the user has typed more characters than the target sentence contains (for example, extra characters at the end), those are appended in a separate char-extra span with a red underline, so over-typing is visually distinct from a wrong-character mismatch rather than silently ignored. This span-per-character approach means the entire sample re-renders on every input event, which is cheap enough at typical sentence lengths (60-90 characters) to run smoothly on every keystroke without any debouncing.

The words-per-minute formula

WPM is calculated using the standard typing-test convention: one "word" equals five characters (including spaces), regardless of actual word boundaries, because this normalizes scoring across sentences with different average word lengths. The formula is words = typed.length / 5, then wpm = Math.round((typed.length / 5) / (elapsedSeconds / 60)). Critically, the timer does not start when the component loads — it starts on the very first input event via a null-check on startTime, matching how real typing tests behave (you should not be penalized for time spent reading the prompt before you start typing). A setInterval running every 100ms recalculates and redisplays the live WPM, accuracy, and elapsed time while the test is in progress, so numbers update smoothly rather than jumping only on keystrokes.

Accuracy scoring and completion detection

computeAccuracy(typed) counts how many typed characters match the target at the same index, divided by the total number of characters typed so far (not the target length), so accuracy reflects the quality of what has actually been typed at any moment — including dips caused by mistakes that were later corrected. The test only completes when typed.length >= target.length && typed === target, an exact string equality check, meaning a single leftover typo blocks completion until the user backspaces and fixes it, mirroring the "you cannot finish with mistakes present" behavior of most typing test tools. On completion, finishTest() stops the interval timer, disables the textarea so no further input is registered, and reveals a results overlay summarizing final WPM, accuracy, and total time.

Random sample rotation and reset flow

Five sample sentences of varying length and vocabulary live in a SAMPLES array; pickSample() selects one at random using Math.floor(Math.random() * SAMPLES.length). Both the header "Try Again" button and the results overlay's "Try Again" button call the same resetTest() function, which clears the interval, resets startTime to null, re-enables the textarea, picks a fresh random sample, and re-renders the target text in its untyped state — ensuring every attempt starts from a clean, consistent baseline with no leftover timer or stale DOM classes from the previous run.

Build with AI

Build, Understand, Optimize, and Extend It With AI

Paste this snippet's HTML, CSS, and JS into an AI coding assistant like Claude and ask it to walk through exactly how renderTarget() builds the per-character span markup on every keystroke, and how the WPM formula and the null-startTime check work together to make sure timing only begins once real typing starts. It's also worth asking the assistant to extend the test meaningfully: request a fixed-duration mode (for example a 60-second countdown where the test ends automatically regardless of completion), a per-word accuracy breakdown highlighting which specific words caused the most retyping, or a results history stored in localStorage so returning users can see their WPM trend over multiple sessions. Because the character-diffing and timing logic are cleanly separated from the DOM rendering, it's a good snippet to ask an assistant to refactor into a reusable typing-test engine you could reuse in other contexts.

Prompt to recreate it

Copy this into your AI assistant of choice to build the effect from scratch, or as a jumping-off point for your own variant:

text
Build a typing speed test in plain HTML, CSS, and JavaScript that measures words-per-minute and accuracy in real time as the user types — no external libraries or fonts.

Requirements:
- Display a sample sentence and provide a text input where the user types it; on every keystroke, re-render the sample text so each character is individually marked correct, incorrect, or not-yet-typed compared against the same-index character the user has typed so far.
- Handle the case where the user types more characters than the sample sentence contains by visually flagging the extra characters distinctly, rather than silently ignoring or crashing on them.
- Start a timer precisely on the user's first keystroke (not on page load), and calculate a live words-per-minute value using the standard convention of one word equaling five characters, updating continuously (for example every 100ms) rather than only on each keystroke.
- Calculate and display a live accuracy percentage based on how many of the characters typed so far exactly match the target at their position.
- Detect completion only when the typed text exactly matches the full target sentence (including catching any leftover uncorrected mistakes), and at that point stop the timer, disable further input, and show a results summary of final WPM, accuracy, and total elapsed time.
- Provide a "Try again" control that resets all state — timer, input value, disabled state, and displayed stats — and selects a new random sentence from a pool of at least four sample sentences of varying length.
- Make sure rapid typing does not cause any visual lag or flicker in the character highlighting, and that backspacing correctly reverts characters from correct/incorrect back to their untyped appearance.

Want to tighten it up first? Run this prompt through the AI Prompt Studio to score it across 8 quality dimensions, catch anti-patterns, and tune the wording for Claude, ChatGPT, or Gemini before you paste it in.

Step by step

How to Use

  1. 1
    Start typing to beginClick into the textarea and start typing the displayed sentence. The timer starts automatically on your first keystroke via the null-check on startTime inside handleInput() — there is no separate start button.
  2. 2
    Watch live character feedbackAs you type, renderTarget() re-renders the sample sentence on every input event, coloring correct characters green (.char-correct) and incorrect ones red (.char-incorrect). Extra characters typed beyond the sentence length appear underlined in red via .char-extra.
  3. 3
    Monitor your live WPM and accuracyThe three stat tiles above the sentence update every 100ms via a setInterval calling updateLiveStats(), showing your current words-per-minute, accuracy percentage, and elapsed time in real time as you type.
  4. 4
    Complete the test and view resultsFinish typing the full sentence exactly as shown — the test only completes when your typed text exactly equals the target string. finishTest() then disables the textarea and reveals an overlay with your final WPM, accuracy, and total time.
  5. 5
    Try again with a new random sentenceClick "Try Again" (either in the footer or on the results overlay) to call resetTest(), which picks a new random sentence from the SAMPLES array, clears the timer, and re-enables the textarea for a fresh attempt.
  6. 6
    Add your own sample sentencesEdit the SAMPLES array at the top of the JS panel to add, remove, or replace sentences. Longer or more complex sentences with punctuation and varied word lengths make for a more challenging or realistic typing test.

Real-world uses

Common Use Cases

Standalone typing speed test tool or landing page feature
Ship this as a self-contained typing test page, the kind of interactive tool that attracts organic search traffic for queries like "typing speed test" or "WPM test online". The exact-match completion logic and live stat tiles give it the same feel as dedicated typing test sites without needing a backend.
Onboarding assessment for data-entry or transcription roles
Recruiting and HR tools for roles requiring fast, accurate typing (customer support, transcription, data entry) can embed this as a quick skills-check step in an application flow, using the reported WPM and accuracy as a screening signal before a candidate proceeds to interview.
Typing tutor and keyboarding education for students
Educational platforms teaching touch-typing can use this component as a practice drill, swapping the SAMPLES array for curriculum-specific sentences (common words, home-row focused phrases, or progressively longer passages) and tracking improvement in WPM and accuracy across repeated Try Again attempts.
Gamified typing challenge with score sharing
Add a leaderboard or daily-challenge wrapper around this component by capturing the final WPM and accuracy values from finishTest() and posting them to a backend, turning a solo typing test into a competitive, shareable game mode similar to how the Reaction Time Tester Game tracks and compares session bests.
Portfolio or resume interactive skill demonstration
Developers building a personal site can use a polished interactive component like this as a portfolio piece demonstrating DOM manipulation, timing logic, and state management skills to potential employers, since the entire implementation is visible and reviewable as a single self-contained file.
Foundation for a multiplayer or timed typing competition
The character-diffing and WPM-calculation logic in this snippet is the same core engine needed for more advanced typing competition features — a fixed 60-second countdown mode, multiplayer races comparing WPM in real time via WebSockets, or a "worst word" analysis highlighting which words caused the most mistakes.

Got questions?

Frequently Asked Questions

Standard typing test convention (used by MonkeyType, 10FastFingers, and most typing tutors) defines one "word" as five characters including spaces, regardless of actual word boundaries. This normalizes the WPM score across sentences with different average word lengths — a sentence full of short words and one full of long words produce comparable, fair WPM figures under this formula, rather than actual word-counting which would unfairly reward or penalize vocabulary choice.

The timer starts on the very first input event where startTime is still null, captured as Date.now() at that moment — not when the page loads or the textarea is focused. This means time spent reading the sentence before typing does not count against you. The timer stops the instant the typed text exactly equals the target string, at which point finishTest() clears the interval and disables further input.

computeAccuracy() counts how many characters in the currently typed text match the target string at the same index, then divides by the total number of characters typed so far (not the target sentence length). This means accuracy reflects real-time quality of your current input — if you make a mistake and then backspace to fix it, accuracy recovers immediately since the incorrect character is no longer part of the typed string being measured.

Any characters typed beyond the target sentence's length are rendered in a separate span with the char-extra class, shown in red with an underline, so over-typing is visually distinguished from simply mistyping a character that exists in the target. Because completion requires exact string equality (typed === target), extra trailing characters will also prevent the test from completing until they are removed.

Yes, edit the SAMPLES array at the top of the JS panel — it is a plain array of strings, and pickSample() selects a random index from whatever length the array currently is via Math.floor(Math.random() * SAMPLES.length). You can add as many sentences as you want, including longer paragraphs, though very long text will make the sample-text panel taller and may need adjusted line-height or a max-height with scroll.