How to Create a Speed Typing Game with HTML, CSS, and JavaScript


By Faraz -

Learn how to build an exciting speed typing game using HTML, CSS, and JavaScript. Follow our step-by-step guide to create your own fun and interactive typing challenge.

how to create a speed typing game with html, css, and javascript.jpg

Table of Contents

  1. Project Introduction
  2. HTML Code
  3. CSS Code
  4. JavaScript Code
  5. Preview
  6. Conclusion

Welcome to our comprehensive tutorial on creating an exciting speed typing game using HTML, CSS, and JavaScript.

In this guide, we will take you on a journey from the inception of the idea to the final implementation of a fully functional typing game. Whether you're an aspiring web developer looking to expand your skill set or simply someone interested in building fun and engaging online experiences, this tutorial is designed to cater to all levels of expertise.

The speed typing game you'll be creating will challenge users to type a given word or sentence as quickly and accurately as possible. Throughout the tutorial, you'll gain hands-on experience in structuring web content with HTML, enhancing its visual appeal with CSS, and adding interactivity and game mechanics with JavaScript. By the end, you'll not only have a functional typing game but also a deeper understanding of how these three fundamental web technologies can work together seamlessly to create captivating user experiences.

So, whether you're here for the thrill of coding, the joy of learning, or the satisfaction of building something cool, let's embark on this coding adventure together and turn your web development aspirations into reality. Let's get started!

Source Code

Step 1 (HTML Code):

To get started, we will first need to create a basic HTML file. In this file, we will include the main structure for our speed testing game.

After creating the files just paste the following codes into your file. Make sure to save your HTML document with a .html extension, so that it can be properly viewed in a web browser.

Here's an explanation of each part:

1. <!DOCTYPE html>: This is a document type declaration, which specifies that the document follows the HTML5 standard.

2. <html lang="en">: This is the opening tag for the HTML document, and it specifies that the document is written in English (with the "en" attribute).

3. <head>: This is the head section of the HTML document, which contains meta-information about the page.

  • <title>Speed Typing Test</title>: This sets the title of the web page, which appears in the browser's title bar or tab.
  • <meta charset="UTF-8" />: This specifies the character encoding for the document as UTF-8, which is a widely used encoding for displaying text in various languages.
  • <meta name="viewport" content="width=device-width" />: This meta tag is used to configure the viewport settings for responsive design, ensuring that the webpage adapts to the width of the user's device.
  • <link rel="stylesheet" href="styles.css" />: This line links an external CSS (Cascading Style Sheets) file named "styles.css" to the HTML document. It's used to apply styles and layout to the page's elements.

4. <body>: This is the body section of the HTML document, where the main content of the webpage is placed.

5. <main>: The <main> element typically encapsulates the main content of the page.

6. <div class="quote-display" id="quoteDisplay"><span></span></div>: This is a container (<div>) with the class "quote-display" and the ID "quoteDisplay." It appears to be a placeholder for displaying text quotes.

7. <section class="typing">: This is a section of the page with the class "typing," presumably containing elements related to the typing test.

8. <hr />: This is an HTML horizontal rule element, used to create a horizontal line or divider.

9. <div class="score">: This is a container for displaying the user's score.

10. <div class="timer">: This is a container for displaying the timer for the typing test.

  • <span class="timer__label">Time:</span>: This is a label for the timer, indicating that it displays the time.
  • <span class="timer__text" id="timer">0</span>: This is the actual timer display, which starts at 0 and presumably updates as the user types.

11. <div="words-per-minute">: There seems to be an error here. It should be <div class="words-per-minute">. This is a container for displaying the words per minute (WPM) count.

  • <span class="words-per-minute__label">Words/min:</span>: This is a label for the WPM count, indicating the unit of measurement.
  • <span class="words-per-minute__text" id="wpm">0</span>: This is where the actual WPM count is displayed and updates as the user types.

12. <textarea class="quote-input" name="quoteInput" id="quoteInput" placeholder="Start typing right here!" cdkFocusInitial></textarea>: This is a text input field (textarea) where users can start typing. It has the class "quote-input," a name attribute, an ID of "quoteInput," a placeholder text, and an attribute "cdkFocusInitial" that suggests it should receive initial focus when the page loads.

13. <script src="script.js"></script>: This line includes an external JavaScript file named "script.js," which is used to add interactivity and functionality to the webpage.

This is the basic structure of our speed-testing game using HTML, and now we can move on to styling it using CSS.

Step 2 (CSS Code):

Once the basic HTML structure of the speed testing game is in place, the next step is to add styling to the game using CSS.

Next, we will create our CSS file. In this file, we will use some basic CSS rules to style our game. Let's break down each part of the code:

1. @import url(;: This line imports a font named "Gotu" from Google Fonts to be used in the webpage. It makes this font available for use in the CSS later.

2. The *, *::before, and *::after selectors are used to target all elements on the page, including pseudo-elements before and after. The following properties are applied to these elements:

  • margin: 0; and padding: 0;: These rules reset the default margin and padding for all elements, effectively removing any spacing around them.
  • box-sizing: border-box;: This rule ensures that the width and height of elements include both the content and padding, preventing unexpected layout issues.
  • font-family: "Gotu", sans-serif;: It sets the default font for all elements to "Gotu," a font imported earlier, and falls back to a generic sans-serif font if "Gotu" is unavailable.
  • font-weight: normal; and font-size: 18px;: These rules set the default font weight to normal and font size to 18 pixels for all elements.

3. body selector: This styles the <body> element of the webpage. It sets the width and height to 100% of the viewport width and height, respectively. It also sets the background color to white (#fff) and the text color to a shade of gray (#414244).

4. main selector: This styles the <main> element of the webpage. It uses CSS Grid to create a two-row layout. The main element takes up the entire width and height of its parent container and adds padding of 3 rems on all sides.

5. quote-display selector: This styles an element with the class "quote-display." It's positioned relatively within the grid and placed in the first row (row 1) at the bottom of the row (using grid-row: 1/2;). Inside this element, there's a <span> with specific font styles for quotes, including font size, font weight, and line spacing. Additionally, there's a pseudo-element ::before used to insert an open-quote character before the text.

6. typing selector: This styles an element with the class "typing." It's also positioned relatively within the grid and placed in the second row (row 2) of the grid. It uses CSS Grid to create a three-column layout for some interactive elements. When hovered over, the <hr> element inside it widens its width, creating a visual effect.

7. hr selector: This styles all <hr> elements. It positions the <hr> element across all columns and sets a border with a specific color, width, and transition effect, creating a growing line animation when hovered over.

8. score selector: This styles an element with the class "score." It's positioned relatively and contains text with a background and box-shadow to create a subtle card-like appearance.

9. quote-input selector: This styles an input element with the class "quote-input." It sets its width, height, padding, background color, border, and placeholder text color. The placeholder text changes color when hovered over.

10. .right, .wrong, and .halp selectors: These style elements with classes "right," "wrong," and "halp." They set specific colors and text decoration for these classes. The .halp class also uses a keyframe animation called "glitch" to create a glitchy effect when applied.

11. @keyframes glitch: This defines a keyframe animation named "glitch" with several steps, creating a glitchy visual effect. It includes transformations, changes in border color, and box-shadow to simulate a glitch.

This will give our speed testing game an upgraded presentation. Create a CSS file with the name of styles.css and paste the given codes into your CSS file. Remember that you must create a file with the .css extension.

@import url(;
*::after {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
  font-family: "Gotu", sans-serif;
  font-weight: normal;
  font-size: 18px;

body {
  width: 100vw;
  height: 100vh;
  background: #fff;
  color: #414244;

main {
  display: grid;
  grid-template-rows: repeat(2, 1fr);
  width: 100%;
  height: 100%;
  padding: 3rem;

.quote-display {
  position: relative;
  grid-row: 1/2;
  align-self: end;
.quote-display span {
  font-size: 2.25rem;
  font-weight: 800;
  line-height: 1.4;
  letter-spacing: 0.1rem;
.quote-display::before {
  content: open-quote;
  position: absolute;
  top: -5rem;
  left: -2rem;
  z-index: -1;
  font-size: 10rem;
  color: #d7d7d8;

.typing {
  position: relative;
  grid-row: 2/-1;
  display: grid;
  grid-template-columns: 33% auto 2rem auto 2rem;
  align-items: start;
  width: 100%;
  height: 100%;
.typing:hover hr {
  width: 75%;

hr {
  grid-column: 1/-1;
  margin-top: 1rem;
  border: 0.25rem solid #4fb578;
  width: 25%;
  transition: width 300ms ease-in-out;
  outline: 0;

.score {
  position: relative;
  grid-column: 3/-2;
  display: flex;
  justify-content: space-between;
  z-index: 2;
  width: 100%;
  margin-top: -1.375rem;
  margin-bottom: -1rem;
  background: #fff;
  padding: 0.25rem 2rem;
  box-shadow: 0 3px 6px rgba(52, 31, 97, 0.16), 0 3px 6px rgba(52, 31, 97, 0.23);

.quote-input {
  grid-column: 2/-1;
  height: calc(50vh - 4rem);
  width: 100%;
  padding: 0 1rem;
  padding-top: 2rem;
  background: #fff;
  border: 0;
  border-radius: 0.2rem;
  resize: none;
  outline: none;
  transition: border 300ms ease-in-out;
.quote-input::placeholder {
  color: #d7d7d8;
  transition: color 300ms ease-in-out;
.quote-input:hover::placeholder {
  color: #4fb578;

.right {
  color: #4fb578;

.wrong {
  color: #b55648;
  text-decoration: line-through;

.halp {
  position: relative;
  border-color: #b55648;
  animation: glitch 300ms;

@keyframes glitch {
  0% {
    transform: translateY(-2%);
    border-color: #414244;
    box-shadow: -1.5px 2.5px #4fa5b5;
  15% {
    transform: translateY(5%);
    box-shadow: 2px -1px #d87dbb;
  45% {
    border-color: #d7d7d8;
    box-shadow: 0.5px -2px #d7d7d8;
  85% {
    border-color: #b55648;
    box-shadow: 1px -1.5px #d87dbb;
  100% {
    transform: translateX(-1%);
    box-shadow: -0.5px 0.5px #4fa5b5;

Step 3 (JavaScript Code):

Finally, we need to create a function in JavaScript. Here's an explanation of the code step by step:

1. Constants and DOM Element Selection:

  • The code begins by defining a constant RANDOM_QUOTE_API_URL, which is the URL for an API that provides random quotes.
  • It selects various HTML elements from the DOM using document.querySelector(). These elements include:
  • quoteDisplayElement: The element where the random quote will be displayed.
  • quoteInputElement: The input element where the user types the quote.
  • timerElement: An element to display the elapsed time.
  • wordsPerMinuteElement: An element to display the user's typing speed in words per minute.
  • divider: An HR element used to visually indicate correct and incorrect typing.

2. Event Listener:

  • An event listener is added to the quoteInputElement. It listens for the "input" event, which triggers whenever the user types something in the input field.
  • When the user types, the code inside this event listener is executed to check the correctness of their typing and calculate their typing speed.

3. Input Handling:

  • Inside the event listener, the code:
  • Retrieves an array of span elements representing individual characters in the displayed quote.
  • Splits the user's input into an array of characters.
  • Initializes variables right and count to keep track of correctness and the number of correctly typed characters.
  • Iterates through each character in the quote and compares it with the corresponding character in the user's input.
  • Adds CSS classes ("right" or "wrong") to each character span based on correctness.
  • Updates the count when a character is typed correctly.

4. Words Per Minute (WPM) Calculation:

  • Calculates the words per minute (WPM) based on the number of correctly typed characters and the time elapsed.
  • The formula used is a rough estimate: (count * 60) / (getTimerTime() * 5), which considers 5 characters per word and adjusts for time.

5. Displaying WPM:

  • Updates the wordsPerMinuteElement with the calculated WPM.

6. Fetching a New Random Quote:

  • If the user types the entire quote correctly (right is true), the getNextQuote() function is called.
  • The getNextQuote() function makes an API request to get a new random quote, clears the previous quote display, and displays the new quote one character at a time.

7. Functions for Fetching and Displaying Quotes:

  • getRandomQuote(): Fetches a random quote from the API and returns its content.
  • getNextQuote(): Calls getRandomQuote() to fetch a new quote, clears the quote display, and displays the new quote.

8. Timer Functions:

  • startTimer(): Initializes a timer to keep track of how long the user takes to type the quote.
  • getTimerTime(): Calculates the time elapsed since the timer was started.

9. Initial Quote Display:

  • Calls getNextQuote() to fetch and display the first random quote when the page loads.

Create a JavaScript file with the name script.js and paste the given codes into your JavaScript file and make sure it's linked properly to your HTML document so that the scripts are executed on the page. Remember, you’ve to create a file with .js extension.

const quoteDisplayElement = document.querySelector("#quoteDisplay");
const quoteInputElement = document.querySelector("#quoteInput");
const timerElement = document.querySelector("#timer");
const wordsPerMinuteElement = document.querySelector("#wpm");
const divider = document.querySelector("hr");

quoteInputElement.addEventListener("input", () => {
  const quoteArray = quoteDisplayElement.querySelectorAll("span");
  const valueArray = quoteInputElement.value.split("");
  let right = true;
  let count = 0;

  quoteArray.forEach((characterSpan, i) => {
    const character = valueArray[i];
    if (character == null) {
      right = false;
    } else if (character === characterSpan.textContent) {
    } else {
      right = false;
  let randomNumber = Math.round(count * 60  / (getTimerTime() * 5) * 10) / 10;
  if (isNaN(randomNumber)) {
    wordsPerMinuteElement.textContent = "0";
  } else {
    wordsPerMinuteElement.textContent = randomNumber;
  if (right) getNextQuote();

function getRandomQuote() {
    .then((response) => response.json())
    .then((data) => data.content)
    .catch(error => console.log(error));

async function getNextQuote() {
  const quote = await getRandomQuote();
  quoteDisplayElement.innerHTML = "";
  quote.split("").forEach((character) => {
    const characterSpan = document.createElement("span");
    characterSpan.textContent = character;
  quoteInputElement.value = null;

let startTime;
function startTimer() {
  timerElement.textContent = 0;
  startTime = new Date();
  setInterval(() => {
    timer.textContent = getTimerTime();
  }, 1000)

function getTimerTime() {
  return Math.floor((new Date() - startTime) / 1000);


Final Output:

how to create a speed typing game with html, css, and javascript.gif


Congratulations on completing this tutorial on creating a speed typing game using HTML, CSS, and JavaScript. You've embarked on a rewarding journey in web development and successfully built an engaging and interactive typing challenge.

Throughout this guide, you've learned how to structure web content with HTML, style it to perfection with CSS, and bring it to life with JavaScript. You've integrated a timer, scoring system, and feedback mechanism, transforming a simple idea into a fully functional game.

We hope you've enjoyed this tutorial and that it has inspired you to explore the world of web development further. Building interactive web applications is not only a valuable skill but also a gateway to endless creativity. So, keep coding, keep learning, and keep creating. The digital world is yours to shape.

Thank you for choosing this tutorial, and we wish you the best of luck in all your web development endeavors!

Code by: Angel

That’s a wrap!

I hope you enjoyed this post. Now, with these examples, you can create your own amazing page.

Did you like it? Let me know in the comments below 🔥 and you can support me by buying me a coffee.

And don’t forget to sign up to our email newsletter so you can get useful content like this sent right to your inbox!

Faraz 😊

End of the article

Subscribe to my Newsletter

Get the latest posts delivered right to your inbox

Latest Post