Create a Stopwatch using React

Are you preparing for a Frontend React developer interview?

Besides tricky theory-based questions, interviewers often test your problem-solving skills with real-world challenges. One unique task is:

“Can you create a stopwatch using React with functional components?”

Sounds simple, right? But it tests your understanding of React hooks, conditional rendering, timing functions, and component state management.

In this guide, we’ll walk through building a fully functional stopwatch in React step-by-step using CodeSandbox. You’ll understand every line of code — with comments, logic, and how to explain it during interviews.


🛠️ Tools & Setup

We’ll be using CodeSandbox — an online editor to quickly run and test React code.

After creating a new React sandbox, you’ll see a screen with a default App.js file. We’ll replace that with our stopwatch implementation.


Step 1: Create Stopwatch UI Elements

Let’s start by building the structure of the stopwatch: Hours, Minutes, and Seconds, along with Start and Reset buttons.

import "./styles.css";

export default function App() {
  return (
    <div className="App">
      <h2>Stopwatch Using React</h2>
      <h4>
        <i>
          By <a href="https://techinterviewhub.in/">Tech Interview Hub</a>
        </i>
      </h4>

      <div>
        <div>
          <p>00</p>
          <p><b>Hours</b></p>
        </div>
        <div>
          <p>00</p>
          <p><b>Minutes</b></p>
        </div>
        <div>
          <p>00</p>
          <p><b>Seconds</b></p>
        </div>
      </div>

      <div>
        <button>Start</button>
        <button>Reset</button>
      </div>
    </div>
  );
}

Step 2: Plan the Functionality

🔁 Stopwatch Logic:

  • Click Start: stopwatch begins
  • Button label changes to Stop
  • Click Stop: stopwatch pauses
  • Click Reset: stopwatch resets to 00:00:00

Step 3: Declare States and Refs

We need two states and one reference:

  • time: current time (in seconds)
  • isRunning: whether stopwatch is active
  • timerRef: to hold the interval ID
import { useState, useRef } from "react";

const [time, setTime] = useState(0); // Total time in seconds
const [isRunning, setIsRunning] = useState(false);
const timerRef = useRef(null); // Holds interval ID

Step 4: Add Toggle Start/Stop Functionality

Here’s where the stopwatch logic comes in:

const toggleStopwatch = () => {
  if (isRunning) {
    setIsRunning(false);
    clearInterval(timerRef.current); // Stop the interval
  } else {
    setIsRunning(true);
    timerRef.current = setInterval(() => {
      setTime((prevTime) => prevTime + 1); // Increment time every second
    }, 1000);
  }
};

📌 What is useRef?

The useRef() hook stores a mutable reference that persists across re-renders without triggering a render itself. We use it here to store the setInterval ID and later clear it.


Step 5: Toggle Button Text

Update the start button to dynamically change its label:

<button onClick={toggleStopwatch}>
  {isRunning ? "Stop" : "Start"}
</button>

Step 6: Convert Time to H:M:S

We’ll convert total seconds into HH:MM:SS format.

const hours = Math.floor(time / 3600);
const minutes = Math.floor((time % 3600) / 60);
const seconds = time % 60;

// Format as 2-digit
const format = (num) => String(num).padStart(2, "0");

Step 7: Display Time on UI

Replace hardcoded values with dynamic ones:

<div>
  <p>{format(hours)}</p>
  <p><b>Hours</b></p>
</div>
<div>
  <p>{format(minutes)}</p>
  <p><b>Minutes</b></p>
</div>
<div>
  <p>{format(seconds)}</p>
  <p><b>Seconds</b></p>
</div>

Step 8: Reset Functionality

const resetWatch = () => {
  clearInterval(timerRef.current); // Stop interval
  setTime(0); // Reset time
  setIsRunning(false); // Reset state
};

<button onClick={resetWatch}>Reset</button>

Step 9: Align Components Horizontally (UI)

Let’s display Hours, Minutes, and Seconds side by side using inline CSS:

<div style={{ display: "flex", justifyContent: "center", gap: "20px" }}>
  {/* Hours, Minutes, Seconds */}
</div>

🧾 Full Code

Here’s the full working code for the stopwatch:

import { useState, useRef } from "react";
import "./styles.css";

export default function App() {
  const [time, setTime] = useState(0);
  const [isRunning, setIsRunning] = useState(false);
  const timerRef = useRef(null);

  const toggleStopwatch = () => {
    if (isRunning) {
      setIsRunning(false);
      clearInterval(timerRef.current);
    } else {
      setIsRunning(true);
      timerRef.current = setInterval(() => {
        setTime((prevTime) => prevTime + 1);
      }, 1000);
    }
  };

  const resetWatch = () => {
    clearInterval(timerRef.current);
    setTime(0);
    setIsRunning(false);
  };

  const hours = Math.floor(time / 3600);
  const minutes = Math.floor((time % 3600) / 60);
  const seconds = time % 60;

  const format = (num) => String(num).padStart(2, "0");

  return (
    <div className="App">
      <h2>Stopwatch Using React</h2>
      <h4>
        <i>
          By <a href="https://techinterviewhub.in/">Tech Interview Hub</a>
        </i>
      </h4>

      <div style={{ display: "flex", justifyContent: "center", gap: "20px" }}>
        <div>
          <p>{format(hours)}</p>
          <p><b>Hours</b></p>
        </div>
        <div>
          <p>{format(minutes)}</p>
          <p><b>Minutes</b></p>
        </div>
        <div>
          <p>{format(seconds)}</p>
          <p><b>Seconds</b></p>
        </div>
      </div>

      <div style={{ marginTop: "20px" }}>
        <button onClick={toggleStopwatch}>
          {isRunning ? "Stop" : "Start"}
        </button>
        <button onClick={resetWatch}>Reset</button>
      </div>
    </div>
  );
}

Conclusion

This stopwatch is a great React interview coding challenge that demonstrates:

  • useState for state management
  • useRef for storing interval ID
  • setInterval and clearInterval for timer control
  • Conditional rendering for dynamic UI

🧠 Pro Tip: During interviews, explain your thought process clearly. Mention why useRef was used instead of useState for timerRef.


🔗 Try it Live

👉 Open Stopwatch on CodeSandbox

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top