JSFiddle - React, Tailwind, and code Playground

by Vijay Pancholi

HTML

<div class="container">
  <h1>Typing Speed Test</h1>
  <p id="quote">Loading...</p>
  <textarea id="input" placeholder="Start typing here..."></textarea>
  <div class="stats">
    <p><strong>WPM:</strong> <span id="wpm">0</span></p>
    <p><strong>Accuracy:</strong> <span id="accuracy">100%</span></p>
    <button onclick="resetTest()">Restart</button>
  </div>
</div>

CSS

body {
  font-family: Arial, sans-serif;
  background: #f0f0f0;
  text-align: center;
  padding: 50px;
}
.container {
  max-width: 600px;
  margin: auto;
  background: #fff;
  padding: 30px;
  border-radius: 12px;
  box-shadow: 0 0 10px rgba(0,0,0,0.1);
}
#quote {
  font-size: 20px;
  margin-bottom: 20px;
}
textarea {
  width: 100%;
  height: 100px;
  font-size: 18px;
  padding: 10px;
}
.stats {
  margin-top: 20px;
}
button {
  margin-top: 10px;
  padding: 8px 20px;
  font-size: 16px;
}

JavaScript

const sentences = [
  "JavaScript is fun to learn.",
  "Practice makes you better.",
  "The quick brown fox jumps over the lazy dog.",
  "Typing games improve your speed and accuracy.",
];

let quote = document.getElementById('quote');
let input = document.getElementById('input');
let wpmDisplay = document.getElementById('wpm');
let accuracyDisplay = document.getElementById('accuracy');

let currentSentence = "";
let startTime = null;
let timerStarted = false;

function loadSentence() {
  currentSentence = sentences[Math.floor(Math.random() * sentences.length)];
  quote.innerText = currentSentence;
  input.value = "";
  wpmDisplay.textContent = 0;
  accuracyDisplay.textContent = "100%";
  startTime = null;
  timerStarted = false;
}

function calculateWPM(text, timeElapsedInSeconds) {
  const words = text.trim().split(/\s+/).length;
  return Math.round((words / timeElapsedInSeconds) * 60);
}

function calculateAccuracy(original, typed) {
  let correct = 0;
  for (let i = 0; i < typed.length; i++) {
    if (typed[i] === original[i]) correct++;
  }
  return Math.round((correct / original.length) * 100);
}

input.addEventListener('input', () => {
  if (!timerStarted) {
    startTime = new Date();
    timerStarted = true;
  }

  const typedText = input.value;
  const elapsedTime = (new Date() - startTime) / 1000;

  const wpm = calculateWPM(typedText, elapsedTime);
  const accuracy = calculateAccuracy(currentSentence, typedText);

  wpmDisplay.textContent = wpm;
  accuracyDisplay.textContent = accuracy + "%";

  if (typedText === currentSentence) {
    input.disabled = true;
  }
});

function resetTest() {
  input.disabled = false;
  loadSentence();
}

window.onload = loadSentence;