Build a Simple Next.js Interactive Typing Speed Test App

In today’s digital world, typing speed and accuracy are crucial skills. Whether you’re a student, a professional, or simply someone who enjoys online activities, the ability to type quickly and efficiently can significantly boost your productivity and overall online experience. This is where a typing speed test app comes in handy. It’s not just a fun exercise; it’s a practical tool for self-improvement, allowing you to track your progress and identify areas where you can improve your typing skills. This article will guide you through building a simple, yet effective, typing speed test application using Next.js, a powerful React framework.

Why Build a Typing Speed Test App?

Creating a typing speed test app offers several benefits:

  • Skill Enhancement: It provides a platform to practice and improve typing speed and accuracy.
  • Real-time Feedback: The app offers immediate feedback on your performance, including words per minute (WPM), accuracy, and errors.
  • Personalized Practice: You can customize the test with different word sets or time limits.
  • Learning Next.js: It’s a fantastic project for learning and practicing Next.js fundamentals, including component creation, state management, and event handling.
  • Portfolio Piece: A well-built typing speed test app can showcase your front-end development skills.

Prerequisites

Before we begin, ensure you have the following installed:

  • Node.js and npm: This is essential for managing project dependencies and running the development server.
  • A code editor: (e.g., VS Code, Sublime Text) to write and edit your code.
  • Basic understanding of HTML, CSS, and JavaScript: Familiarity with these languages will make the development process smoother.

Setting Up the Next.js Project

Let’s start by creating a new Next.js project. Open your terminal and run the following command:

npx create-next-app typing-speed-test-app

This command creates a new Next.js project with the specified name. Navigate into the project directory:

cd typing-speed-test-app

Now, start the development server:

npm run dev

This command starts the development server, and you can access your app in your browser at http://localhost:3000.

Project Structure

Next.js projects have a specific structure. Here’s a basic overview:

  • pages/: This directory contains your application’s pages. Each file in this directory represents a route.
  • public/: This directory holds static assets like images, fonts, and other files.
  • styles/: This directory is where you’ll put your CSS or styling files.

Building the Core Components

Let’s build the essential components for our typing speed test app.

1. The Typing Test Component (pages/index.js)

This will be the main component of our application. Open pages/index.js and replace its content with the following code:

import React, { useState, useEffect, useRef } from 'react';

const TypingTest = () => {
  const [text, setText] = useState('');
  const [userInput, setUserInput] = useState('');
  const [startTime, setStartTime] = useState(null);
  const [endTime, setEndTime] = useState(null);
  const [wpm, setWpm] = useState(0);
  const [accuracy, setAccuracy] = useState(100);
  const [errors, setErrors] = useState(0);
  const [isTestRunning, setIsTestRunning] = useState(false);
  const textRef = useRef(null);

  const words = [
    "apple", "banana", "cherry", "date", "elderberry", "fig", "grape", "honeydew", "kiwi", "lemon",
    "mango", "nectarine", "orange", "papaya", "quince", "raspberry", "strawberry", "tangerine", "ugli", "vanilla",
    "watermelon", "xigua", "yuzu", "zucchini", "apricot", "blueberry", "cantaloupe", "dragonfruit", "eggplant", "fava"
  ];

  useEffect(() => {
    setText(generateText(50)); // Generate 50 words initially
  }, []);

  const generateText = (numWords) => {
    let generatedText = '';
    for (let i = 0; i  {
    const input = e.target.value;
    setUserInput(input);

    if (!isTestRunning) {
      setIsTestRunning(true);
      setStartTime(new Date());
    }

    // Calculate accuracy and errors in real-time
    calculateAccuracyAndErrors(input);
  };

  const calculateAccuracyAndErrors = (input) => {
    const typedWords = input.split(' ');
    const originalWords = text.split(' ');
    let correctChars = 0;
    let errorCount = 0;

    for (let i = 0; i  0 ? ((correctChars / totalChars) * 100) : 100;
    setAccuracy(Math.round(accuracyPercentage));
    setErrors(errorCount);
  };

  const calculateWpm = () => {
    if (startTime && endTime) {
      const timeInMinutes = (endTime.getTime() - startTime.getTime()) / 60000;
      const wordCount = userInput.split(' ').length;
      const calculatedWpm = Math.round(wordCount / timeInMinutes);
      setWpm(calculatedWpm);
    }
  };

  const handleTestEnd = () => {
    setEndTime(new Date());
    setIsTestRunning(false);
    calculateWpm();
  };

  useEffect(() => {
    if (isTestRunning) {
      if (userInput.split(' ').length === text.split(' ').length) {
        handleTestEnd();
      }
    }
  }, [userInput, text, isTestRunning]);

  const handleReset = () => {
    setUserInput('');
    setStartTime(null);
    setEndTime(null);
    setWpm(0);
    setAccuracy(100);
    setErrors(0);
    setIsTestRunning(false);
    setText(generateText(50));
  };

  return (
    <div style="{{">
      <h1>Typing Speed Test</h1>
      <div style="{{">
        <p style="{{">Type the following text:</p>
        <p style="{{">{text}</p>
      </div>
      <div style="{{">
        
      </div>
      <div style="{{">
        <div>WPM: {wpm}</div>
        <div>Accuracy: {accuracy}%</div>
        <div>Errors: {errors}</div>
      </div>
      <div>
        <button style="{{">
          Reset
        </button>
      </div>
    </div>
  );
};

export default TypingTest;

This component includes the following:

  • State Variables: Variables to store the text to be typed, the user’s input, start and end times, WPM, accuracy, errors, and a flag to indicate if the test is running.
  • Word List: An array of words for the typing test.
  • useEffect Hook (Initial Text): When the component mounts, it generates a set of words to be typed.
  • generateText Function: Generates a string of words from the words array.
  • handleInputChange Function: Handles the user’s input, starts the timer when the user begins typing, and calculates real-time accuracy and errors.
  • calculateAccuracyAndErrors Function: Calculates the accuracy and error count based on the user’s input.
  • calculateWpm Function: Calculates the words per minute (WPM) after the test ends.
  • handleTestEnd Function: Handles the end of the test, recording the end time and calculating WPM.
  • useEffect Hook (Test Completion): This useEffect hook triggers when the user has typed all the words.
  • handleReset Function: Resets the test, clearing input, resetting the timer, and generating new text.
  • JSX Structure: The JSX structure displays the text to be typed, an input field for user input, and displays the WPM, accuracy, and error count. It also includes a reset button.

2. Styling (styles/globals.css)

To style the app, open styles/globals.css and add the following:

html, body {
  padding: 0;
  margin: 0;
  font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
  background-color: #f4f4f4;
}

a {
  color: inherit;
  text-decoration: none;
}

* {
  box-sizing: border-box;
}

This CSS provides basic styling for the app, including setting the font and background color.

Step-by-Step Instructions

Let’s walk through the steps to build and refine the typing speed test app.

1. Component Structure and Layout

The TypingTest component is the core of our application. It’s responsible for:

  • Displaying the text to be typed.
  • Providing an input field for the user.
  • Tracking the user’s input.
  • Calculating and displaying the WPM, accuracy, and errors.

The layout consists of a main container, a section for the text, an input field, and a display area for the results. The styling is kept simple for clarity.

2. State Management

We use React’s useState hook to manage the app’s state. The state variables include:

  • text: The text the user needs to type.
  • userInput: The text the user has typed.
  • startTime: The start time of the test.
  • endTime: The end time of the test.
  • wpm: The words per minute.
  • accuracy: The accuracy percentage.
  • errors: The number of typing errors.
  • isTestRunning: A boolean flag to indicate if the test is running.

These state variables are updated based on user input and the test’s progress.

3. Generating the Text

The generateText function is responsible for generating the text for the typing test. It selects random words from the words array and concatenates them into a string. The number of words is controlled by the numWords parameter.

4. Handling User Input

The handleInputChange function is triggered whenever the user types in the input field. It:

  • Updates the userInput state with the user’s input.
  • Starts the timer (by setting the startTime) when the user starts typing.
  • Calls calculateAccuracyAndErrors to update the accuracy and error count in real-time.

5. Calculating Accuracy and Errors

The calculateAccuracyAndErrors function compares the user’s input with the original text. It calculates the accuracy percentage and counts the number of errors. The results are updated in real-time as the user types.

6. Calculating WPM

The calculateWpm function calculates the words per minute (WPM) after the test is completed. It uses the start and end times, along with the number of words typed, to calculate the WPM. The result is then updated in the wpm state variable.

7. Ending the Test

The handleTestEnd function is called when the test is completed. It sets the endTime, calculates the WPM, and sets isTestRunning to false.

8. Resetting the Test

The handleReset function is called when the user clicks the “Reset” button. It resets all the state variables to their initial values and generates a new set of words for the test.

Common Mistakes and How to Fix Them

Here are some common mistakes and how to address them:

  • Incorrect Timing: Make sure your timer accurately measures the time taken by the user. Double-check your time calculations. Use new Date() to get the current timestamp and calculate the difference between start and end times.
  • Accuracy Calculation Errors: The accuracy calculation should correctly compare the user’s input with the original text. Make sure you’re properly comparing the typed words with the original words. Consider edge cases like extra spaces or missing words.
  • State Updates Not Triggering Re-renders: Ensure that state updates are correctly triggering re-renders. Use the useState hook correctly and avoid directly mutating state variables.
  • Input Field Not Clearing: If the input field doesn’t clear after the test, double-check that you’re correctly resetting the userInput state in your reset function.
  • Incorrect WPM Calculation: Ensure that the WPM calculation is correctly dividing the number of words by the time taken (in minutes).
  • Performance Issues with Large Text: If you use a very large amount of text, your app might slow down. Consider techniques like virtualized lists or lazy loading to improve performance.
  • Ignoring Edge Cases: Always consider edge cases, such as the user typing faster than the text can display or handling special characters. Test your app thoroughly.

Enhancements and Features

Here are some ideas to enhance your typing speed test app:

  • Customizable Text: Allow users to enter their own text for the test.
  • Difficulty Levels: Implement different difficulty levels by adjusting the word count or the complexity of the words.
  • User Profiles: Add user profiles to track progress and save scores.
  • Themes: Allow users to choose different themes for the app.
  • Sound Effects: Add sound effects for key presses or errors.
  • Leaderboard: Implement a leaderboard to show the top scores.
  • Keyboard Highlighting: Highlight the keys being typed on a virtual keyboard.
  • Accessibility: Make the app accessible by using semantic HTML and providing keyboard navigation.

SEO Best Practices

To ensure your app ranks well on Google, follow these SEO best practices:

  • Keyword Optimization: Use relevant keywords like “typing speed test,” “WPM test,” and “typing practice” naturally throughout your content and code (e.g., in the title, meta description, and alt text for images).
  • Descriptive Titles and Meta Descriptions: Create compelling titles and meta descriptions that accurately reflect the content of your app.
  • Clean and Readable Code: Write clean, well-commented code that is easy for search engines to crawl.
  • Mobile-Friendly Design: Ensure your app is responsive and works well on all devices.
  • Fast Loading Speed: Optimize your code and images to ensure your app loads quickly. Use tools like Lighthouse to measure and improve your performance.
  • Structured Data: Consider using structured data markup (schema.org) to provide more information about your app to search engines.

Summary / Key Takeaways

Building a typing speed test app with Next.js is an excellent project for learning and improving your front-end development skills. This tutorial has provided a solid foundation for creating a functional and engaging application. You’ve learned how to set up a Next.js project, create components, manage state, handle user input, and calculate essential metrics like WPM and accuracy. Remember to focus on clean code, proper state management, and user-friendly design. By implementing the suggestions for enhancements, you can create a more feature-rich and engaging typing speed test app. The skills you gain from this project will be valuable for future web development endeavors. Keep practicing, experimenting, and refining your skills. The journey of a thousand lines of code begins with a single keystroke, and with each line, you become a more proficient developer.