How to Make Stopwatch in React

In this article, we are going to make a stopwatch in React. Like a basic stopwatch, we will have a display to show time, then we will have basic buttons for start, stop, resume, and reset. As soon we hit the start button, a timer will be started and two buttons will appear stop and reset. By clicking stop, the timer will be stopped, and a resume button will appear. Lastly, the reset button will reset the timer back to 0 again.

So basically this is going to be a beginner-friendly project, so let’s make this project step-by-step.

Pre-requisites to Make Stopwatch in React

  • Basic knowledge of ReactJS.
  • Basic knowledge of React hooks.
  • Basic knowledge of React props.
  • Good knowledge of React Components.

Creating App Component

Let us start with the App.js component, we have imported DisplayComponent.js and BtnComponent.js components, in which we will add structure for button and display. Then we also imported the useState hook, so we could make use of it to get variable time. Now we have created a state for time with initial 0 values for ms,s,m,h, which is actually for milliseconds, seconds, minutes, and hours.

Then in a return statement, we have called these two components in a div. And we have passed time as a prop for <DisplayComponent/>. Okay, so this is not for all for App.js we will make some changes as we progress in the Application.

import React, {useState} from 'react';
import DisplayComponent from './Components/DisplayComponent';
import BtnComponent from './Components/BtnComponent';
import './App.css';

function App() {
  const [time, setTime] = useState({ms:0, s:0, m:0, h:0});

return (
     <div className="clock-holder">
    <div className="main-section">
          <div className="stopwatch">
               <DisplayComponent time={time}/>
               <BtnComponent/>
          </div>
     </div>
    </div>
  );
}

export default App;

Setting up Display Component

In this component, we have to set up our display for the timer. Here in return(), we have added a function called h(), in this function, we have just checked whether the hour (here ‘h’) is 0 or not, if yes then we will not show the hour in our timer. If h is greater than 0 then we will show hour and return as span.

Then we added 3 span tags for a minute, millisecond, and for second. in all these span, we have added functionality to add a 0 before the actual timer if any of these times is below 10. Here we have used props to get the values from the App.js component, and the changes made in the App component are directly reflected here.

import React from 'react';

function DisplayComponent(props) {
  const h = () => {
     if(props.time.h === 0){
       return '';
     }else {
       return <span>{(props.time.h >= 10)? props.time.h : "0"+ props.time.h}</span>;
     }
  }
  return (
    <div>
       {h()}&nbsp;&nbsp;
       <span>{(props.time.m >= 10)? props.time.m : "0"+ props.time.m}</span>&nbsp;:&nbsp;
       <span>{(props.time.s >= 10)? props.time.s : "0"+ props.time.s}</span>&nbsp;:&nbsp;
       <span>{(props.time.ms >= 10)? props.time.ms : "0"+ props.time.ms}</span>
    </div>
  );
}

export default DisplayComponent;
Stopwatch in React

Adding Functionalities of Stopwatch

Now let’s customize the App component a little bit, here we have added some props in <BtnComponent/> like start, stop, resume, reset and status with all perspective function calls. We will define these functions one by one, but before that, we have added 2 more states, one for interval and the other for status with initial values.

After that in the start function, we called a run() function, and we updated the status with value 1, also we updated the value of setInterv with a run function for 10ms. So each 10ms run, the function will be called. In this run function, we have updated the values of hours, minutes, and seconds if it hits certain conditions. For these condition checking, we have added some temporary variables to store the values of parameters of the time state

For stop(), we have just updated the status value with 2 and for the reset() function we will clear out the timer and set our time status back to 0. Lastly, for the resume, we just called the start() function to run again the timer.

const [time, setTime] = useState({ms:0, s:0, m:0, h:0});
  const [interv, setInterv] = useState();
  const [status, setStatus] = useState(0);
  // Not started = 0
  // started = 1
  // stopped = 2

  const start = () => {
    run();
    setStatus(1);
    setInterv(setInterval(run, 10));
  };

  var updatedMs = time.ms, updatedS = time.s, updatedM = time.m, updatedH = time.h;

  const run = () => {
    if(updatedM === 60){
      updatedH++;
      updatedM = 0;
    }
    if(updatedS === 60){
      updatedM++;
      updatedS = 0;
    }
    if(updatedMs === 100){
      updatedS++;
      updatedMs = 0;
    }
    updatedMs++;
    return setTime({ms:updatedMs, s:updatedS, m:updatedM, h:updatedH});
  };

  const stop = () => {
    clearInterval(interv);
    setStatus(2);
  };

  const reset = () => {
    clearInterval(interv);
    setStatus(0);
    setTime({ms:0, s:0, m:0, h:0})
  };

  const resume = () => start();


  return (
    <div className="main-section">
     <div className="clock-holder">
          <div className="stopwatch">
               <DisplayComponent time={time}/>
               <BtnComponent status={status} resume={resume} reset={reset} stop={stop} start={start}/>
          </div>
     </div>
    </div>
  );
}

Managing The Timer Props

Lastly, we have to make use of these props in <BtnComponent/>, here we are checking the status value from the status prop, If it is 0 that means the stopwatch will be in the initial state, and at that time we will create a button named Start and also add an onClick listener, in which we will call the start function from the App component using props.start.

If the status value is 1 then we will add the Stop and Reset button, and we will call the props.stop and prop.reset functions. Remember that, initially status will be 0, so we will get the Start button but as soon status becomes 1 then we will get the Stop and Reset button and the previous button (Start) won’t show up.

Similarly, for props.status == 2, we will add the resume and reset button with props.resume and props.reset function call.

import React from 'react';

function BtnComponent(props) {
  return (
    <div>
      {(props.status === 0)? 
        <button className="stopwatch-btn stopwatch-btn-gre"
        onClick={props.start}>Start</button> : ""
      }

      {(props.status === 1)? 
        <div>
          <button className="stopwatch-btn stopwatch-btn-red"
                  onClick={props.stop}>Stop</button>
          <button className="stopwatch-btn stopwatch-btn-yel"
                  onClick={props.reset}>Reset</button>
        </div> : ""
      }

     {(props.status === 2)? 
        <div>
          <button className="stopwatch-btn stopwatch-btn-gre"
                  onClick={props.resume}>Resume</button>
          <button className="stopwatch-btn stopwatch-btn-yel"
                  onClick={props.reset}>Reset</button>
        </div> : ""
      }
     
    </div>
  );
}

export default BtnComponent;
Stopwatch in React

Customizing The Application

Now our structure is pretty good, and we have added almost everything but before going to the next move, let’s add some colors and customize this calculator, so this can look like a calculator at least. I won’t go deep in CSS because CSS is actually dependent on you and this is not that hard to put color or something. So if you want the same CSS then use the below CSS.

App.css

body {
  background:#2C3E50;
}

* {
  padding: 0px;
  margin: 0px;
  box-sizing: border-box;
}

.main-section {
  background: transparent;
  max-width: 600px;
  width: 90%;
  height: 500px;
  margin: 30px auto;
}

.clock-holder {
  width: 100%;
  background: #fff;
  margin: 30px auto;
  position: relative;
}


.stopwatch {
  padding: 60px 0px;
  text-align: center;
}
.stopwatch span{
  background:#00ABA9;
  color: #fff;
  display: inline-block;
  font-family: monospace;
  font-size: 22px;
  padding: 20px;
  border-radius: 5px;
  width: 70px;
}

.stopwatch .stopwatch-btn {
  background: #fff;
  margin-top: 30px;
  margin-left: 5px;
  border: none;
  padding: 12px 20px;
  font-size: 16px;
  text-transform: uppercase;
  width: 150px;
  transition: background 1s;
  cursor: pointer;
}
.stopwatch .stopwatch-btn-red{
  border: 2px solid #C85454;
  color: #C85454;
}
.stopwatch .stopwatch-btn-yel{
  border: 2px solid #FFC900;
  color: #FFC900;
}

.stopwatch .stopwatch-btn-gre{
  border: 2px solid #00ABA9;
  color: #00ABA9;
}
.stopwatch .stopwatch-btn-red:hover {
  background: #C85454;
  border: 2px solid #C85454;
  color: #fff;
}
.stopwatch .stopwatch-btn-yel:hover {
  background: #FFC900;
  border: 2px solid #FFC900;
  color: #fff;
}
.stopwatch .stopwatch-btn-gre:hover {
  background: #00ABA9;
  border: 2px solid #00ABA9;
  color: #fff;
}

Full Source Code to Make Stopwatch in React

index.js

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

App.js

import React, {useState} from 'react';
import DisplayComponent from './Components/DisplayComponent';
import BtnComponent from './Components/BtnComponent';
import './App.css';

function App() {
  const [time, setTime] = useState({ms:0, s:0, m:0, h:0});
  const [interv, setInterv] = useState();
  const [status, setStatus] = useState(0);
  // Not started = 0
  // started = 1
  // stopped = 2

  const start = () => {
    run();
    setStatus(1);
    setInterv(setInterval(run, 10));
  };

  var updatedMs = time.ms, updatedS = time.s, updatedM = time.m, updatedH = time.h;

  const run = () => {
    if(updatedM === 60){
      updatedH++;
      updatedM = 0;
    }
    if(updatedS === 60){
      updatedM++;
      updatedS = 0;
    }
    if(updatedMs === 100){
      updatedS++;
      updatedMs = 0;
    }
    updatedMs++;
    return setTime({ms:updatedMs, s:updatedS, m:updatedM, h:updatedH});
  };

  const stop = () => {
    clearInterval(interv);
    setStatus(2);
  };

  const reset = () => {
    clearInterval(interv);
    setStatus(0);
    setTime({ms:0, s:0, m:0, h:0})
  };

  const resume = () => start();


  return (
    <div className="main-section">
     <div className="clock-holder">
          <div className="stopwatch">
               <DisplayComponent time={time}/>
               <BtnComponent status={status} resume={resume} reset={reset} stop={stop} start={start}/>
          </div>
     </div>
    </div>
  );
}

export default App;

DisplayComponent.js

import React from 'react';

function DisplayComponent(props) {
  const h = () => {
     if(props.time.h === 0){
       return '';
     }else {
       return <span>{(props.time.h >= 10)? props.time.h : "0"+ props.time.h}</span>;
     }
  }
  return (
    <div>
       {h()}&nbsp;&nbsp;
       <span>{(props.time.m >= 10)? props.time.m : "0"+ props.time.m}</span>&nbsp;:&nbsp;
       <span>{(props.time.s >= 10)? props.time.s : "0"+ props.time.s}</span>&nbsp;:&nbsp;
       <span>{(props.time.ms >= 10)? props.time.ms : "0"+ props.time.ms}</span>
    </div>
  );
}

export default DisplayComponent;

BtnComponent.js

import React from 'react';

function BtnComponent(props) {
  return (
    <div>
      {(props.status === 0)? 
        <button className="stopwatch-btn stopwatch-btn-gre"
        onClick={props.start}>Start</button> : ""
      }

      {(props.status === 1)? 
        <div>
          <button className="stopwatch-btn stopwatch-btn-red"
                  onClick={props.stop}>Stop</button>
          <button className="stopwatch-btn stopwatch-btn-yel"
                  onClick={props.reset}>Reset</button>
        </div> : ""
      }

     {(props.status === 2)? 
        <div>
          <button className="stopwatch-btn stopwatch-btn-gre"
                  onClick={props.resume}>Resume</button>
          <button className="stopwatch-btn stopwatch-btn-yel"
                  onClick={props.reset}>Reset</button>
        </div> : ""
      }
     
    </div>
  );
}

export default BtnComponent;

App.css

body {
  background:#2C3E50;
}

* {
  padding: 0px;
  margin: 0px;
  box-sizing: border-box;
}

.main-section {
  background: transparent;
  max-width: 600px;
  width: 90%;
  height: 500px;
  margin: 30px auto;
}

.clock-holder {
  width: 100%;
  background: #fff;
  margin: 30px auto;
  position: relative;
}


.stopwatch {
  padding: 60px 0px;
  text-align: center;
}
.stopwatch span{
  background:#00ABA9;
  color: #fff;
  display: inline-block;
  font-family: monospace;
  font-size: 22px;
  padding: 20px;
  border-radius: 5px;
  width: 70px;
}

.stopwatch .stopwatch-btn {
  background: #fff;
  margin-top: 30px;
  margin-left: 5px;
  border: none;
  padding: 12px 20px;
  font-size: 16px;
  text-transform: uppercase;
  width: 150px;
  transition: background 1s;
  cursor: pointer;
}
.stopwatch .stopwatch-btn-red{
  border: 2px solid #C85454;
  color: #C85454;
}
.stopwatch .stopwatch-btn-yel{
  border: 2px solid #FFC900;
  color: #FFC900;
}

.stopwatch .stopwatch-btn-gre{
  border: 2px solid #00ABA9;
  color: #00ABA9;
}
.stopwatch .stopwatch-btn-red:hover {
  background: #C85454;
  border: 2px solid #C85454;
  color: #fff;
}
.stopwatch .stopwatch-btn-yel:hover {
  background: #FFC900;
  border: 2px solid #FFC900;
  color: #fff;
}
.stopwatch .stopwatch-btn-gre:hover {
  background: #00ABA9;
  border: 2px solid #00ABA9;
  color: #fff;
}

Output

Stopwatch in React

Check out the video reference here:

You may also like:

Reactjs Guru
Reactjs Guru

Welcome to React Guru, your ultimate destination for all things React.js! Whether you're a beginner taking your first steps or an experienced developer seeking advanced insights.

React tips & tutorials delivered to your inbox

Don't miss out on the latest insights, tutorials, and updates from the world of ReactJs! Our newsletter delivers valuable content directly to your inbox, keeping you informed and inspired.

One comment

Leave a Reply

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

Table of Contents