In this tutorial, you will learn how to create a countdown timer with React js and React hooks like useState and useEffect. You will also install and use React Icons in order to create the Play, Pause and Stop button and of course the watch icon.
A countdown timer is a visual representation of the time remaining until an event or deadline. It is often used in games, quizzes, auctions, and other time-limited activities.
The React Countdown timer overview
Here is a step by step description of the code for the React countdown timer:
- The code starts by importing the necessary dependencies from the React library, as well as an additional
Timer
component and some icons from thereact-icons/bs
library. It then sets the background color of the body element to#282c34
. - Next, the
CountdownTimer
component is defined as a function component. It has several state variables:hours
,minutes
,seconds
,milliseconds
, andisRunning
. The component also has a state variable calledshowEndScreen
which is an object with two properties:show
andmessage
. - The component has a
useEffect
hook that is called whenever the component renders or any of the state variables listed in the second argument of the hook (milliseconds
,seconds
,minutes
,hours
,isRunning
, andshowEndScreen.show
) are updated. - Within the
useEffect
hook, an interval is set usingsetInterval
, which is called every 10 milliseconds. This interval counts down the timer by decreasing the value ofmilliseconds
by 1 each time. Ifmilliseconds
reaches 0, it resets to 99 andseconds
is decreased by 1. This process is repeated forminutes
andhours
. - If the timer reaches 00:00:00:00, the
showEndScreen
state variable is updated to show the end screen, and the timer is reset using theresetTimer
function. - The
startTimer
function is called when the “Start” button is clicked. It checks if any time has been set for the timer, and if so, sets theisRunning
state variable totrue
and hides the end screen by updating theshowEndScreen
state variable. If no time has been set, it displays an alert. - The
pauseTimer
function is called when the “Pause” button is clicked. It sets theisRunning
state variable tofalse
, which causes theuseEffect
hook to stop the interval. - The
stopTimer
function is called when the
Install React
To get started, we’ll need to set up a new React project. If you already have a project set up, you can skip this step. To create a new project, we’ll use the create-react-app
command-line tool:
npx create-react-app countdown-timer
// or
npx create-react-app . // if folder already exists.
Next, we’ll install some additional dependencies that we’ll be using in our countdown timer. We’ll be using the react-icons/bs
library for some buttons that we’ll be adding to the UI, so let’s install that first:
cd countdown-timer
npm start // Start the application.
App CSS
Copy and replace the css in your App.css with the code provided below
.App {
text-align: center;
}
.App-logo {
height: 40vmin;
pointer-events: none;
}
@media (prefers-reduced-motion: no-preference) {
.App-logo {
animation: App-logo-spin infinite 20s linear;
}
}
.App-header {
background-color: #282c34;
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: calc(10px + 2vmin);
color: white;
}
.App-link {
color: #61dafb;
}
@keyframes App-logo-spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
@import url("https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap");
@import url("https://fonts.googleapis.com/css2?family=Open+Sans:ital,wght@0,300;0,400;0,500;0,600;0,700;0,800;1,300;1,400;1,500;1,600;1,800&display=swap");
@import url("https://fonts.googleapis.com/css2?family=Poppins:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap");
@import url("https://fonts.googleapis.com/css2?family=Lato:ital,wght@0,100;0,300;0,400;0,700;0,900;1,100;1,300;1,400;1,700;1,900&display=swap");
@import url("https://fonts.googleapis.com/css2?family=Raleway:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap");
* {
margin: 0;
padding: 0;
box-sizing: border-box;
text-decoration: none;
list-style-type: none;
}
/* Roboto Font */
body {
font-family: "Roboto", sans-serif;
}
/*Container class*/
.container {
max-width: 900px;
margin: 0 auto;
}
.d-flex {
display: flex;
justify-content: center;
align-items: center;
}
.d-flex.flex-column {
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
}
/*Title and Subtitle */
.title {
font-size: 3.75rem;
font-weight: 500;
margin: 3rem 0;
}
.text-light {
color: #f8f9fa;
}
/*Main Btn Class*/
.btn {
margin: 0.25rem 0.125rem;
padding: 0.35rem 1.25rem;
font-family: inherit;
font-weight: 500;
font-size: 1rem;
letter-spacing: 0.6px;
border-radius: 0.3rem;
color: #fff;
background-color: #000;
border: none;
box-shadow: 0 2px 5px rgba(51, 51, 51, 0.3);
transition: 0.3s ease;
}
.btn:hover,
.btn-accept:hover,
.btn-warning:hover {
cursor: pointer;
box-shadow: none;
transition: 0.3s ease;
background: rgba(0, 0, 0, 0.75);
}
/* Btn Types*/
.btn-danger {
background-color: #dc3545;
color: white;
}
.btn-danger:hover {
background: rgba(220, 53, 69, 0.75);
}
.btn-warning {
background-color: #ffc107;
color: white;
color: #000;
}
.btn-warning:hover {
background: rgba(255, 193, 7, 0.75);
}
.btn-accept {
background-color: #284ea7;
color: white;
}
.btn-accept:hover {
background: rgba(40, 78, 167, 0.75);
}
.btn-lg {
margin: 0.3125rem 0.15625rem;
padding: 0.4375rem 1.5625rem;
font-size: 20px;
}
Create a countdown timer
With the dependencies installed, we can now start building our countdown timer. We’ll start by setting up the basic structure of our component. We’ll be creating a new file called Timer.js
in the src
directory of our project:
import React, { useState, useEffect } from "react";
function CountdownTimer() {
const [hours, setHours] = useState(0);
const [minutes, setMinutes] = useState(0);
const [seconds, setSeconds] = useState(0);
const [milliseconds, setMilliseconds] = useState()
We’ve defined several state variables for our timer: hours
, minutes
, seconds
, and milliseconds
. These variables will be used to store the current time left on the timer.
Next, we’ll add a useEffect
hook to our component. This hook will be called whenever the component renders or any of the state variables listed in the second argument of the hook (in this case, milliseconds
, seconds
, minutes
, and hours
) are updated.
Within the useEffect
hook, we’ll set an interval using setInterval
. This interval will be called every 10 milliseconds, and it will count down the timer by decreasing the value of milliseconds
by 1 each time. If milliseconds
reaches 0, it will reset to 99 and seconds
will be decreased by 1. This process will be repeated for minutes
and hours
.
Now that we have the basic structure of our countdown timer set up, we’ll add some buttons to control it. We’ll add “Start”, “Pause”, “Stop”, and “Reset” buttons to the UI. Let’s start with the “Start” button:
function startTimer() {
if (hours !== 0 || minutes !== 0 || seconds !== 0 || milliseconds !== 0) {
setIsRunning(true);
} else {
window.alert("Add Time.");
}
}
return (
<div>
<button onClick={startTimer}>
<BsFillPlayFill />
</button>
</div>
);
The “Start” button checks if any time has been set for the timer. If time has been set, it sets the isRunning
state variable to true
, which will start the interval in the useEffect
hook. If no time has been set, it displays an alert.
Next, let’s add the “Pause” button:
function pauseTimer() {
setIsRunning(false);
}
return (
<div>
<button onClick={startTimer}>
<BsFillPlayFill />
</button>
<button onClick={pauseTimer}>
<BsPauseFill />
</button>
</div>
);
The “Pause” button simply sets the isRunning
state variable to false
, which will pause the interval in the useEffect
hook.
Next, let’s add the “Stop” and “Reset” buttons:
function stopTimer() {
resetTimer();
}
function resetTimer() {
setIsRunning(false);
setMilliseconds(0);
setSeconds(0);
setMinutes(0);
setHours(0);
}
return (
<div>
<button onClick={startTimer}>
<BsFillPlayFill />
</button>
<button onClick={pauseTimer}>
<BsPauseFill />
</button>
<button onClick={stopTimer}>
<BsStopFill />
</button>
<button onClick={resetTimer}>Reset</button>
As I mentioned earlier, one potential feature we could add to our countdown timer is an “End Screen” that is displayed when the time runs out. To implement this, we’ll need to add a state variable called showEndScreen
, which will store an object with a show
property and a message
property. We’ll also need to add a condition to our useEffect
hook to check if the time has run out and set showEndScreen.show
to true
if it has.
Here’s how we can implement this feature:
const [showEndScreen, setShowEndScreen] = useState({
show: false,
message: "Happy coding in 2023!",
});
useEffect(() => {
// existing code
if (hours === 0 && minutes === 0 && seconds === 0 && milliseconds === 1) {
setShowEndScreen({ ...showEndScreen, show: true });
resetTimer();
}
}, [milliseconds, seconds, minutes, hours, isRunning, showEndScreen.show]);
return (
<div>
{showEndScreen.show && (
<h1 className="title text-light">{showEndScreen.message}</h1>
)}
</div>
);
Now, when the time runs out, the “End Screen” will be displayed with the message “Happy coding in 2023!”.
That’s it! We now have a fully functional countdown timer with the ability to set the time, start, pause, stop, and reset the timer, as well as display an “End Screen” when the time runs out.
Complete Code for the React Countdown timer
Countdown Timer component
You will also need to install reacticons to provide the Play, Pause and Stop icons.
import React, { useState, useEffect } from "react";
import Timer from "./Timer";
import { BsFillPlayFill, BsPauseFill, BsStopFill } from "react-icons/bs";
document.body.style.background = "#282c34";
export default function CountdownTimer() {
const [hours, setHours] = useState(0);
const [minutes, setMinutes] = useState(0);
const [seconds, setSeconds] = useState(0);
const [milliseconds, setMilliseconds] = useState(0);
const [isRunning, setIsRunning] = useState(null);
// End of Time
const [showEndScreen, setShowEndScreen] = useState({
show: false,
message: "Happy coding in 2023",
});
useEffect(() => {
let interval;
if (isRunning) {
interval = setInterval(() => {
if (milliseconds > 0) {
setMilliseconds((milliseconds) => milliseconds - 1);
} else if (seconds > 0) {
setSeconds((seconds) => seconds - 1);
setMilliseconds(99);
} else if (minutes > 0) {
setMinutes((minutes) => minutes - 1);
setSeconds(59);
setMilliseconds(99);
} else if (hours > 0) {
setHours((hours) => hours - 1);
setMinutes(59);
setSeconds(59);
setMilliseconds(99);
}
}, 10);
}
if (hours === 0 && minutes === 0 && seconds === 0 && milliseconds === 1) {
setShowEndScreen({ ...showEndScreen, show: true });
resetTimer();
}
return () => clearInterval(interval);
}, [milliseconds, seconds, minutes, hours, isRunning, showEndScreen.show]);
// Start Pause & Stop functions
// Start
function startTimer() {
if (hours !== 0 || minutes !== 0 || seconds !== 0 || milliseconds !== 0) {
setIsRunning(true);
setShowEndScreen({ ...showEndScreen, show: false });
} else {
window.alert("Add Time.");
}
}
// Pause
function pauseTimer() {
setIsRunning(false);
}
// Stop
function stopTimer() {
resetTimer();
setShowEndScreen({ ...showEndScreen, show: false });
}
function resetTimer() {
setIsRunning(false);
setMilliseconds(0);
setSeconds(0);
setMinutes(0);
setHours(0);
}
// Handlers
const changeSeconds = (e) => {
setSeconds(e.target.value);
};
const changeMinutes = (e) => {
setMinutes(e.target.value);
};
const changeHours = (e) => {
setHours(e.target.value);
};
return (
<div>
{showEndScreen.show && (
<h1 className="title text-light">{showEndScreen.message}</h1>
)}
<Timer
milliseconds={milliseconds}
seconds={seconds}
minutes={minutes}
hours={hours}
changeSeconds={changeSeconds}
changeMinutes={changeMinutes}
changeHours={changeHours}
/>
<br />
{!isRunning && (
<button className="btn btn-accept btn-lg" onClick={startTimer}>
<BsFillPlayFill />
</button>
)}
{isRunning && (
<button className="btn btn-warning btn-lg" onClick={pauseTimer}>
<BsPauseFill />
</button>
)}{" "}
<button className="btn btn-danger btn-lg" onClick={stopTimer}>
<BsStopFill />
</button>
</div>
);
}
Timer component
import React from "react";
import { BsStopwatch } from "react-icons/bs";
import styled from "styled-components";
const TimerWrapper = styled.div`
margin-top: 30vh;
width: 600px;
margin-left: auto;
margin-right: auto;
background-color: #222;
color: #eee;
border-radius: 5px;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 5px 4px 6px rgba(0, 0, 0, 0.4);
padding: 1rem 0;
.stop-watch {
font-size: 6rem;
margin-right: 1rem;
}
label {
margin-bottom: 0.5rem;
}
input {
width: 100px;
margin-right: 1rem;
color: #282c34;
outline: none;
border: none;
font-size: 4.5rem;
font-weight: 600;
text-align: center;
padding: 0rem 0.5rem;
border-radius: 5px;
}
input:hover {
background-color: #928f8f;
}
`;
export default function Timer({
milliseconds,
seconds,
minutes,
hours,
changeSeconds,
changeMinutes,
changeHours,
}) {
return (
<TimerWrapper>
<BsStopwatch className="stop-watch " />
<div className="d-flex flex-column">
<label>hh</label>
<input value={hours} onChange={changeHours} />
</div>{" "}
<div className="d-flex flex-column">
<label>mm</label>
<input value={minutes} onChange={changeMinutes} />
</div>{" "}
<div className="d-flex flex-column">
<label>ss</label>
<input value={seconds} onChange={changeSeconds} />
</div>{" "}
<div className="d-flex flex-column">
<label>ms</label>
<input value={milliseconds} />
</div>
</TimerWrapper>
);
}
Video Tutorial on Youtube
Check out the full detailed tutorial on my YouTube Channel for the React Countdown timer.
Want to become a web developer ?
Get complete web development courses on HTML, CSS , JavaScript, Bootstrap, Visual Studio Code, Responsive design and much more…