A fully interactive typing speed test built with Next.js App Router. This project includes multiple test modes, difficulty levels, live typing metrics, result states, and persistent personal-best tracking.
- Overview
- Features
- Tech Stack
- Project Structure
- Getting Started
- Available Scripts
- How It Works
- Design Notes
- Data Model
- Accessibility
- Deployment
- Future Improvements
This app is based on the Frontend Mentor Typing Speed Test challenge and is implemented as a single interactive client page in a Next.js 16 project.
Users can:
- Start typing tests from a button or directly by clicking passage text and typing.
- Choose passage difficulty (
Easy,Medium,Hard). - Switch between:
Timed (60s)mode (countdown behavior), andPassagemode (count-up timer, ends on completion).
- See live
WPM,Accuracy, andTime. - Get char-by-char visual feedback while typing.
- Restart with a new random passage.
- View contextual result screens after each run.
- Keep their best score saved between sessions.
- Start test via CTA button.
- Start test by focusing the passage area and typing.
- Difficulty selector:
- pill buttons on desktop,
- dropdowns on mobile.
- Mode selector:
- pill buttons on desktop,
- dropdowns on mobile.
- Restart button to reset state and load a new passage.
- Real-time WPM calculation based on correct characters.
- Real-time accuracy calculation using total key presses and mistakes.
- Visual states for each character:
- correct: green,
- incorrect: red + underline,
- current cursor: highlighted.
- Backspace is supported; historical mistakes still count toward accuracy.
- Result card includes:
- WPM,
- Accuracy,
- Correct/Incorrect character totals.
- First completed run sets baseline (
Baseline Established!). - New personal best shows celebration (
High Score Smashed!) with confetti styling. - Normal completion state (
Test Complete!) for non-PB runs. - Best WPM persisted in
localStorage.
- Next.js 16.2.4 (App Router)
- React 19.2.4
- TypeScript
- CSS (custom properties + responsive styles in global stylesheet)
typing-speed/
├── app/
│ ├── globals.css # Global tokens + all challenge styling
│ ├── layout.tsx # Root layout + local Sora font
│ └── page.tsx # Main typing test logic and UI
├── assets/
│ ├── fonts/ # Sora font files
│ └── images/ # Challenge icons/pattern assets
├── design/ # Reference JPGs (desktop/mobile states)
├── data.json # Passages grouped by difficulty
└── README.md
- Node.js
18.18+(or newer LTS recommended) - npm (comes with Node.js)
npm installnpm run devThen open:
http://localhost:3000
npm run dev- Start local development server.npm run build- Build production bundle.npm run start- Start production server from built output.npm run lint- Run ESLint checks.
- Passages are loaded from
data.json. - A random passage is selected from the active difficulty.
- Restart/difficulty/mode changes trigger new passage selection (avoiding immediate same-ID repeats when possible).
- Timer starts when typing begins (or via start CTA).
Timed (60s)mode:- timer effectively behaves as countdown (
60 - elapsed), - test auto-completes at 60 seconds or earlier if passage is finished.
- timer effectively behaves as countdown (
Passagemode:- timer counts up,
- test completes only when full passage is typed.
WPM=(correctChars / 5) / minutesElapsed.Accuracy=((totalKeys - mistakes) / totalKeys) * 100.- Incorrect character count tracks mistakes at insertion time.
- Local storage key:
typing-speed-personal-best. - Best score is loaded on mount.
- On completion:
- no existing best -> baseline set,
- higher WPM than current best -> best updated,
- otherwise best remains unchanged.
- Color tokens and typography follow
style-guide.md. - Local Sora variable font is used via
next/font/local. - Mobile and desktop patterns are both implemented.
- Hover/focus states are included for interactive controls.
data.json shape:
{
"easy": [{ "id": "easy-1", "text": "..." }],
"medium": [{ "id": "medium-1", "text": "..." }],
"hard": [{ "id": "hard-1", "text": "..." }]
}Each passage entry contains:
id(string): unique passage identifier.text(string): text to type.
- Keyboard-accessible controls for mode, difficulty, restart, and start action.
- Focus-visible styles for controls and passage interaction area.
- Semantic labels for key interactive regions/inputs.
- Color contrast aligned with dark UI design intent.
This app can be deployed on any platform that supports Next.js, such as:
- Vercel
- Netlify
- Render
For Vercel, import the repo and deploy with default Next.js settings.
- Add optional test durations (
15s,30s,120s). - Add typing history charts (session trends over time).
- Add customizable themes and font size controls.
- Add keyboard sound/feedback toggles.
- Add user profile and cloud-synced high scores.
