Since my coding bootcamp ended, I have been working on simple React and JavaScript projects and learning along the way. Last week, I came across the challenge of generating a progress bar using React when a button is clicked. The challenge was to display multiple progress bars when the ‘Add’ button is clicked. Here is the codepen for that challenge – https://codepen.io/cguntur/pen/PwYRWqb. After doing that challenge, I wanted to build one that can count down and also display a dynamic progress bar.
The Challenge
I wanted to build a progress bar using React with a countdown timer where I can choose the time in minutes.
I looked into a lot of tutorials and then finally was able to build the progress bar. You can see the entire code here – https://codepen.io/cguntur/pen/dPbdBLv
The Process
I setup the site using React Vite. I created a Components folder inside the src folder and created the file ProgressBarWithDuration.jsx
I added the CSS modules to use with the progress bar – ProgressBar.module.css
inside the assets/css folder.
When the page is loaded, there is an initial text that gives the instructions on what to do. Once the timer is started, it shows the countdown in minutes and seconds along with the progress bar. Once the timer ends, the progress bar is not shown anymore, but the text “Times Up!” shows up.
I had some difficulty building this one even though it seems simple enough. I was trying to put together a countdown timer and a progress bar. So, I built a simple count down timer that accepted an input for the total minutes.Then, I integrated that code with the progress bar.
But, since it was a count down, I wanted the progress bar to go from 100% to 0%, which was rather easy. After this was working, I wanted to change the color of the text on the progress bar when it hits 50%. I looked a few tutorials online and finally added the function getColor which takes the progress as the input value and changes the text color when the progress it at 50%.
Progress bar preview
Initially, the isActive
is false and when the start timer button is clicked, it is set to true. When the timer is active, AddProgressBar
displays the progress bar. The custom duration entered in the input box is passed on to the AddProgressBar
and it uses this to display the progress from 100% to 0%.
Here is the code:
import React, { useState, useEffect, useRef } from 'react';
import styles from '../../assets/CSS/ProgressBar.module.css';
const ProgressBarWithDuration = () => {
const inputRef = useRef();
const [customTime, setCustomTime] = useState(""); // Initialize progress at 0
const [timeLeft, setTimeLeft] = useState(""); // Timer value
const [isActive, setIsActive] = useState(false); // To control the timer
const [progressDone, setProgressDone] = useState(false);
const [progress, setProgress] = useState(100);
var customTimeInMilliSeconds = customTime * 60 * 1000;
var customTimeInSeconds = customTime * 60;
var seconds = customTimeInSeconds - (customTime * 60);
useEffect(() => {
let timer;
if(isActive && timeLeft > 0){
timer = setTimeout(() =>{
setTimeLeft((prevTime) => prevTime - 1);
}, 1000);
} else if(timeLeft === 0){
setIsActive(false); // Stop the timer when it reaches zero
setProgressDone(true);
}
return () => clearTimeout(timer); // Cleanup the timer
}, [timeLeft, isActive]);
var minutes = Math.floor(timeLeft / 60);
var seconds = timeLeft - minutes * 60;
if(seconds < 10){
seconds = "0"+seconds;
}
const handleInputChange = (event) => {
setCustomTime(inputRef.current.value);
}
const handleButtonClick = () => {
setTimeLeft(customTimeInSeconds); // Set countdown duration (in seconds)
setIsActive(true); // Activate the timer
setProgressDone(false);
}
return(
<>
<div className={`${styles.countDown}`} style={{ textAlign: "center", marginTop: "20px" }}>
<input type="number" ref={inputRef} onChange={handleInputChange} value={customTime} placeholder="Enter time in minutes" />
<button onClick={handleButtonClick}>
{isActive ? "Counting Down..." : "Start Timer"}
</button>
<div style={{ fontSize: "2rem", margin: "20px" }}>
{!isActive && !progressDone && (
"Enter Time and Press the start button"
)}
{isActive && (
`${minutes}:${seconds}`
)}
{!isActive && progressDone && (
"Times Up!"
)}
</div>
{isActive ?
<AddProgressBar duration={customTimeInMilliSeconds} /> :
""
}
</div>
</>
)
}
Here is the code for the AddProgressBar
const AddProgressBar = ({duration}) =>{
const [progress, setProgress] = useState(100);
// Gradually fill the progress bar
useEffect(() => {
const interval = 10; // Update interval in milliseconds
const increment = (100 / duration) * interval;
const timer = setInterval(() => {
setProgress((prev) => {
if (prev <= 0) {
clearInterval(timer);
return 0;
}
return prev - increment; // Increment progress by 1% every 150ms
});
}, interval);
return () => clearInterval(timer); // Cleanup on unmount
}, []);
// Generate the text color based on progress
const getColor = (value) => {
var color = "255";
if(value < 50){
color = "0";
}
return `rgb(${color}, ${color}, ${color})`;
};
return (
<>
<div className={`${styles.progressBarContainer}`}>
<div className={`${styles.progressBar}`} style={{ width: `${progress}%` }}></div>
<span className={`${styles.label}`} style={{color: `${getColor(progress)}`}}>{`${Math.round(progress)}%`}</span>
</div>
</>
);
}