Below is an example React component for a progress bar that has Start, Pause, Stop, and Reset buttons. The component uses a timer (setInterval) to update the progress value, and different buttons change the component's state:
progress (0β100) tracks the bar width.status indicates if the progress is "idle", "running", "paused", "stopped", or "completed"."completed".import React, { useState, useRef, useEffect } from 'react'; function ProgressBar() { const [progress, setProgress] = useState(0); const [status, setStatus] = useState("idle"); // idle, running, paused, stopped, completed const intervalRef = useRef(null); // Start or resume progress const startProgress = () => { // If already running or completed/stopped, do nothing if (status === "running" || status === "completed" || status === "stopped") return; setStatus("running"); intervalRef.current = setInterval(() => { setProgress(prev => { if (prev >= 100) { clearInterval(intervalRef.current); setStatus("completed"); return 100; } return prev + 1; // Increment progress by 1% per tick }); }, 100); // Update every 100ms }; // Pause the progress const pauseProgress = () => { if (status === "running") { clearInterval(intervalRef.current); setStatus("paused"); } }; // Stop the progress completely (cannot be resumed until reset) const stopProgress = () => { if (status === "running" || status === "paused") { clearInterval(intervalRef.current); setStatus("stopped"); } }; // Reset to initial state const resetProgress = () => { clearInterval(intervalRef.current); setProgress(0); setStatus("idle"); }; // Cleanup on unmount useEffect(() => { return () => clearInterval(intervalRef.current); }, []); return ( <div style={{ padding: "20px", maxWidth: "400px" }}> <div style={{ height: "30px", border: "1px solid #ccc", borderRadius: "5px", overflow: "hidden", marginBottom: "10px" }}> <div style={{ width: `${progress}%`, height: "100%", background: "green", transition: "width 0.1s" }}></div> </div> <div style={{ marginBottom: "10px" }}>Progress: {progress}%</div> <button onClick={startProgress} disabled={status === "running" || status === "completed" || status === "stopped"}>Start</button> <button onClick={pauseProgress} disabled={status !== "running"}>Pause</button> <button onClick={stopProgress} disabled={status !== "running" && status !== "paused"}>Stop</button> <button onClick={resetProgress}>Reset</button> </div> ); } export default ProgressBar;
Start Button :
Initiates the timer if the progress is idle or paused. It wonβt restart if already running, completed, or stopped.
Pause Button :
Clears the interval, freezing the progress.
Stop Button :
Clears the interval and sets the state to "stopped", disallowing resume until the progress is reset.
Reset Button :
Resets the progress to 0 and the status to "idle", allowing you to start over.
This component demonstrates a simple progress bar that updates on an interval and provides control buttons to manage its state.
=====================================================
Below is a complete example of a reusable Progress Bar component implemented as an ES6 class in plain JavaScript. You can reuse this component by instantiating it on any container element.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Reusable Progress Bar Component</title> <style> .progress-wrapper button { margin-right: 5px; margin-top: 5px; } </style> </head> <body> <!-- Container to mount the progress bar component --> <div id="app"></div> <script> class ProgressBar { constructor(container) { this.container = container; this.progress = 0; this.status = "idle"; // possible values: "idle", "running", "paused", "stopped", "completed" this.intervalId = null; this.createDOM(); this.updateUI(); } createDOM() { // Create wrapper element this.wrapper = document.createElement("div"); this.wrapper.classList.add("progress-wrapper"); // Create progress container element this.progressContainer = document.createElement("div"); this.progressContainer.style.cssText = ` width: 400px; height: 30px; border: 1px solid #ccc; border-radius: 5px; overflow: hidden; margin-bottom: 10px; `; // Create the actual progress bar element this.progressBar = document.createElement("div"); this.progressBar.style.cssText = ` height: 100%; background: green; width: 0%; transition: width 0.1s; `; this.progressContainer.appendChild(this.progressBar); // Create progress text element this.progressText = document.createElement("div"); this.progressText.style.marginBottom = "10px"; this.progressText.textContent = "Progress: 0%"; // Create control buttons this.startBtn = document.createElement("button"); this.startBtn.textContent = "Start"; this.pauseBtn = document.createElement("button"); this.pauseBtn.textContent = "Pause"; this.stopBtn = document.createElement("button"); this.stopBtn.textContent = "Stop"; this.resetBtn = document.createElement("button"); this.resetBtn.textContent = "Reset"; // Append all elements into the wrapper this.wrapper.appendChild(this.progressContainer); this.wrapper.appendChild(this.progressText); this.wrapper.appendChild(this.startBtn); this.wrapper.appendChild(this.pauseBtn); this.wrapper.appendChild(this.stopBtn); this.wrapper.appendChild(this.resetBtn); // Append the wrapper to the provided container element this.container.appendChild(this.wrapper); // Attach event listeners to control buttons this.startBtn.addEventListener("click", () => this.start()); this.pauseBtn.addEventListener("click", () => this.pause()); this.stopBtn.addEventListener("click", () => this.stop()); this.resetBtn.addEventListener("click", () => this.reset()); } updateUI() { this.progressBar.style.width = `${this.progress}%`; this.progressText.textContent = `Progress: ${this.progress}%`; } start() { if (this.status === "running" || this.status === "completed" || this.status === "stopped") return; this.status = "running"; this.intervalId = setInterval(() => { if (this.progress >= 100) { clearInterval(this.intervalId); this.progress = 100; this.status = "completed"; this.updateUI(); } else { this.progress++; this.updateUI(); } }, 100); } pause() { if (this.status === "running") { clearInterval(this.intervalId); this.status = "paused"; } } stop() { if (this.status === "running" || this.status === "paused") { clearInterval(this.intervalId); this.status = "stopped"; } } reset() { clearInterval(this.intervalId); this.progress = 0; this.status = "idle"; this.updateUI(); } } // Usage example: // Instantiate the ProgressBar component in the container with id "app" const appContainer = document.getElementById("app"); const myProgressBar = new ProgressBar(appContainer); </script> </body> </html>
ES6 Class Component
The ProgressBar class encapsulates the componentβs state and DOM structure.
progress, status, and intervalId.DOM Creation
The createDOM() method creates all necessary elements (progress container, bar, text, and buttons) and appends them to the container. Inline styles and class names are used for basic styling.
UI Update
The updateUI() method adjusts the progress bar's width and updates the displayed percentage.
Control Methods
start(): Starts/resumes progress using setInterval.pause(): Pauses progress by clearing the interval.stop(): Stops progress permanently until a reset.reset(): Resets the progress to 0 and status to "idle".Event Listeners
Buttons are wired up to call the corresponding methods on click.
This reusable component can be instantiated multiple times in different containers if needed.
Test your understanding with 3 quick questions