Countdown timers are essential features in user interfaces. They are used to create urgency and encourage user engagement in various experiences. Countdown timers are especially useful in coordinating virtual events across different time zones, organizing event registrations, scheduling ecommerce sales, and much more.
In this article, we will look at some of the best React countdown component libraries and explore how to create your own custom timers.
useRef
HookBefore using existing libraries for countdown timers, it’s useful to know how to create one from scratch with React useRef
Hook. Understanding this will help you see the challenges that countdown libraries address and give you the skills to make your own library when necessary.
A countdown timer has three main parts: time storage, time updates, and cleanup. The useRef
Hook is important because it helps us keep track of the timer interval without causing the component to re-render each time.
Let’s break down the implementation step by step:
import React, { useState, useRef, useEffect } from 'react'; const CountdownTimer = ({ initialTime, onComplete }) => { // State to hold the current time remaining const [timeRemaining, setTimeRemaining] = useState(initialTime); // Reference to hold our interval ID const intervalRef = useRef(null); useEffect(() => { // Start the countdown intervalRef.current = setInterval(() => { setTimeRemaining(prevTime => { if (prevTime <= 1) { // Clear interval when we reach zero clearInterval(intervalRef.current); onComplete?.(); // Call completion handler if provided return 0; } return prevTime - 1; }); }, 1000); // Cleanup function to clear interval when component unmounts return () => { if (intervalRef.current) { clearInterval(intervalRef.current); } }; }, []); // Empty dependency array means this effect runs once on mount // Convert seconds to hours, minutes, seconds const hours = Math.floor(timeRemaining / 3600); const minutes = Math.floor((timeRemaining % 3600) / 60); const seconds = timeRemaining % 60; return ( <div className="countdown-timer"> {hours.toString().padStart(2, '0')}: {minutes.toString().padStart(2, '0')}: {seconds.toString().padStart(2, '0')} </div> ); };
First, we use useState
to maintain the current countdown value. While we could store this in a ref
as well, using state ensures our component re-renders when the time changes, updating what the user sees. Learn the difference between useState
and useRef
in this guide.
The useRef
Hook creates our intervalRef
, which stores the ID returned by setInterval
. This reference is important because it persists between renders without causing re-renders itself, allows us to clear the interval from any point in our component, and prevents memory leaks by enabling cleanup when the component unmounts.
The useEffect
Hook orchestrates our timer’s lifecycle. Inside it, we set up the interval to decrement our timer every second, use a cleanup function to clear the interval when the component unmounts, and implement the empty dependency array to ensure our effect runs only once when the component mounts.
While this simple version works, a countdown timer for real use can consider several special cases:
import React, { useState, useRef, useEffect } from 'react'; const EnhancedCountdownTimer = ({ initialTime, onComplete, onTick, isPaused = false }) => { const [timeRemaining, setTimeRemaining] = useState(initialTime); const intervalRef = useRef(null); const previousTime = useRef(Date.now()); const clearTimer = () => { if (intervalRef.current) { clearInterval(intervalRef.current); intervalRef.current = null; } }; useEffect(() => { if (isPaused) { clearTimer(); return; } intervalRef.current = setInterval(() => { const currentTime = Date.now(); const deltaTime = Math.floor((currentTime - previousTime.current) / 1000); previousTime.current = currentTime; setTimeRemaining(prevTime => { const newTime = Math.max(0, prevTime - deltaTime); onTick?.(newTime); // Notify parent of time update if (newTime === 0) { clearTimer(); onComplete?.(); } return newTime; }); }, 1000); return clearTimer; }, [isPaused, onComplete, onTick]); // Reset hook to handle initialTime changes useEffect(() => { setTimeRemaining(initialTime); previousTime.current = Date.now(); }, [initialTime]); return ( <div className="countdown-timer"> {formatTime(timeRemaining)} </div> ); }; // Helper function to format time const formatTime = (totalSeconds) => { const hours = Math.floor(totalSeconds / 3600); const minutes = Math.floor((totalSeconds % 3600) / 60); const seconds = totalSeconds % 60; return `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`; };
This improved version considers several real use case factors:
setTimeout
or setInterval
don’t run exactly on time due to browser issues or system loadisPaused
prop, showing how to manage user actionsonTick
callback lets parent components respond to time changes, which is useful for working with other UI parts or business rulesclearTimer
function makes sure we don’t leave any leftover intervals that could lead to memory leaks.See the different examples in action on Code Sandbox.
Building your own countdown timer offers several advantages:
However, it also comes with challenges:
When choosing a countdown library for your React project, it’s important to know what features set a good timing solution apart from a simple one. Let’s look at some key points to consider.
Modern web applications need countdown displays that fit well with their designs.
The best countdown libraries offer plenty of ways to customize without losing performance or accuracy. Customization features include styling options based on components, display control with render props or functions, formatting, and localization for time units, animation hooks for transitions, and accessibility with proper ARIA attributes.
A good countdown library should, obviously, keep time accurately.
While JavaScript’s setTimeout
and setInterval
might work for simple timing, they can drift over long periods. High-quality countdown libraries use methods like syncing with server time, using algorithms to adjust for changes in system clocks, accurate time tracking with Performance.now()
, and batching updates to reduce performance issues when running multiple timers.
Performance is crucial when using many countdown timers or making frequent updates.
The best countdown libraries use optimization techniques to keep things running smoothly. They focus on efficient update batching, shared timing loops for multiple countdowns, good memory management for finished or canceled timers, optimal use of React’s reconciliation process, and smart throttling and debouncing for quick updates.
How easily a countdown library fits into existing workflows can determine its success.
This includes everything from setup to ongoing maintenance. Important integration features include strong TypeScript support, clear error messages, thorough documentation, few peer dependencies, manageable bundle size, and support for server-side rendering and hydration.
The success of a countdown library over time depends a lot on community support and maintenance. Important factors include regular updates, prompt issue resolution, thorough test coverage, clear guidelines for contributions, and the size and engagement of the user community.
Now that you know what to look for when choosing a React countdown component library, let’s review some of the best countdown libraries available.
React Countdown is a popular countdown component library in the React ecosystem. It provides an easy-to-use API and strong customization features, making it versatile and reliable. The library works well for both simple and complex countdowns while keeping accurate time.
The library has several advantages that make it a good choice. First, it provides high accuracy because of its advanced timing system. Instead of just using setInterval
, it combines different methods to keep time accurately over long periods. This is especially important for long countdowns, such as for event or product launches.
The renderer
prop gives you full control over how things look. It also provides an autoStart
control for automatic or manual start, utility functions such as zeroPad
, calcTimeDelta
, and formatTimeDelta
to assist in formatting and calculating time values, and an API (e.g., start
, pause
, and stop
) for controlling the countdown via a ref
.
Here’s an example of React Countdown’s basic usage:
import React from 'react'; import Countdown from 'react-countdown'; const Completionist = () => <span>Time's up!</span>; const renderer = ({ hours, minutes, seconds, completed }) => { if (completed) { return <Completionist />; } else { return ( <span> {hours}:{minutes}:{seconds} </span> ); } }; const MyCountdown = () => ( <Countdown date={Date.now() + 10000} renderer={renderer} /> ); export default MyCountdown;
React/React Native Countdown Circle Timer is a lightweight React and React Native component that renders a countdown timer in a circular shape with color and progress animations. The library is known for its ability to create visually appealing circular progress indicators with minimal setup, offering color transitions and smooth animations that provide immediate user feedback about time progression, making it effective for timed quizzes, workout intervals, cooking timers, and meeting countdown displays.
The library also supports advanced customization through its comprehensive API; it uses a single request AnimationFrame
loop for efficient animation, supports smooth color transitions, and allows developers to define custom content within the circle’s center. The library is compatible with both iOS and Android platforms, making it versatile for various applications.
The customization options include setting the countdown duration, defining color configurations for different time segments, managing the play state of the timer, and adjusting the stroke width and size of the SVG element.
Here’s an example of React Countdown Circle Timer’s usage:
import { CountdownCircleTimer } from 'react-countdown-circle-timer'; const CircularTimer = () => { return ( <CountdownCircleTimer isPlaying duration={60} colors={['#004777', '#F7B801', '#A30000']} colorsTime={[60, 30, 0]} onComplete={() => { // Return true to repeat the animation return { shouldRepeat: true, delay: 1.5 } }} > {({ remainingTime, color }) => ( <div style={{ color }}> <div className="text-2xl font-bold">{remainingTime}</div> <div className="text-sm">seconds</div> </div> )} </CountdownCircleTimer> ); };
You can check out all the customization options the library offers here.
react-flip-clock-countdown is a new library for React that creates a 3D animated flip-clock countdown component. It makes countdowns on your website more engaging and dynamic. react-flip-clock-countdown is good for situations where visual appeal matters. It is suitable for product launch countdowns, event marketing pages, interactive presentations, gaming interfaces, and timers for special offers.
react-flip-clock-countdown allows you to set a target date and time and customize labels for days, hours, minutes, and seconds. You can also control the visibility of labels and separators.
The library lets you style different parts of the countdown, adjust the flip animation duration, and choose whether the countdown hides after it finishes. Additionally, it provides event callbacks to handle actions when the countdown completes or at each tick, enabling you to show specific components or messages.
Here’s an example of its usage:
import React from 'react'; import FlipClockCountdown from '@leenguyen/react-flip-clock-countdown'; import '@leenguyen/react-flip-clock-countdown/dist/index.css'; const App = () => { return ( <FlipClockCountdown to={new Date().getTime() + 24 * 3600 * 1000 + 5000} // 24 hours from now labels={['Days', 'Hours', 'Minutes', 'Seconds']} labelStyle={{ fontSize: 14, color: '#000' }} digitBlockStyle={{ width: 40, height: 60, fontSize: 48 }} separatorStyle={{ size: 12, color: '#000' }} duration={0.5} hideOnComplete={false} onComplete={() => alert('Countdown completed!')} > <div>Countdown Complete!</div> </FlipClockCountdown> ); }; export default App;
You can check out all the customization props react-flip-clock-countdown offers here.
react-timer-hook takes a different approach by providing a collection of timing-related hooks rather than components. It was designed to manage timers, countdowns, and stopwatch functionalities within React components, which makes it quite flexible and ideal for developers who want to build custom timer interfaces.
The hook-based approach of react-timer-hook offers several advantages:
The React component offers three primary hooks: useTimer
, useStopwatch
, and useTime
, which manage countdown and stopwatch timers respectively. It provides comprehensive control methods like start
, pause
, resume
, and restart
for managing timer states. Customization options include autoStart
configuration, onExpire
callback function, and initial time offsets for stopwatches.
Here is how react-timer-hook separates logic from presentation:
import { useTimer } from 'react-timer-hook'; const Timer = ({ expiryTimestamp }) => { const { seconds, minutes, hours, days, isRunning, start, pause, resume, restart, } = useTimer({ expiryTimestamp, onExpire: () => console.warn('Timer expired!') }); return ( <div className="timer-container"> <div className="timer-display"> <span>{days}</span>:<span>{hours}</span>: <span>{minutes}</span>:<span>{seconds}</span> </div> <div className="timer-controls"> {isRunning ? ( <button onClick={pause}>Pause</button> ) : ( <button onClick={resume}>Resume</button> )} <button onClick={() => { // Restart timer with new expiry date const time = new Date(); time.setSeconds(time.getSeconds() + 300); restart(time); }} > Restart (5 min) </button> </div> </div> ); };
The use-timer library is similar to react-timer-hook in that it offers a simple way to create countdown timers by focusing on providing a lightweight, easy-to-use timer hook. Its simplicity makes it a great choice for basic timing needs. It also offers flexibility for custom uses.
This library works well for:
Here’s an example of use-timer’s basic usage:
import React from 'react'; import { useTimer } from 'use-timer'; const TimerComponent = () => { const { time, start, pause, reset, status } = useTimer({ initialTime: 0, timerType: 'INCREMENTAL', interval: 1000, step: 1, autostart: false, onTimeOver: () => console.log('Time is over'), onTimeUpdate: (time) => console.log('Time updated:', time), }); return ( <div> <p>Elapsed time: {time} seconds</p> <p>Status: {status}</p> <button onClick={start}>Start</button> <button onClick={pause}>Pause</button> <button onClick={reset}>Reset</button> </div> ); }; export default TimerComponent;
Let’s take a look at all the React countdown components we’ve discussed to compare their features:
Characteristic | react-countdown | react-countdown-circle-timer | react-flip-clock-countdown | react-timer-hook | use-timer |
---|---|---|---|---|---|
API type | Component-based | Component-based | Component-based | Hook-based | Hook-based |
Animation support | Custom (via renderer) | Built-in SVG animations | Built-in 3D animation | Manual implementation | Manual implementation |
Styling flexibility | High (custom renderer) | Medium (predefined circle) | Medium | High (bring your own UI) | High (bring your own UI) |
Props/Configuration options | Extensive | Moderate | Moderate | Moderate | Basic |
Time format customization | Yes (via renderer) | Yes (via children) | Yes (via children) | Manual | Manual |
TypeScript support | Full | Full | Full | Full | Full |
SSR compatible | Yes | Yes | Yes | Yes | Yes |
Learning curve | Low to Medium | Low | Low | Low | Very Low |
Documentation quality | Excellent | Good | Good | Good | Good |
Active maintenance | High | High | Medium | Medium | Medium |
Browser support | Modern browsers + IE11 | Modern browsers | Modern browsers | Modern browsers | Modern browsers |
Best for | Complex countdown needs | Visual countdown experiences | Visual countdown experiences | Custom timer implementations | Simple timing requirements |
Using countdown timers in your React applications can boost user engagement and encourage desired actions. By learning how to create timers and exploring your options for third-party libraries, you can choose the best method for your project.
By focusing on performance, customization, ease of integration, and long-term maintenance, you can smoothly add countdown timers to your React projects, making the user experience more dynamic and engaging.
I hope this article has given you helpful tips about React countdown libraries. Let me know if you think of any React countdown component libraries I might have missed!
Install LogRocket via npm or script tag. LogRocket.init()
must be called client-side, not
server-side
$ npm i --save logrocket // Code: import LogRocket from 'logrocket'; LogRocket.init('app/id');
// Add to your HTML: <script src="https://cdn.lr-ingest.com/LogRocket.min.js"></script> <script>window.LogRocket && window.LogRocket.init('app/id');</script>
Developers can take advantage of the latest release of .NET MAUI 9 to build better user experiences that more accurately react and respond to changes in their applications.
As a PM, you can assess your team dynamics with the drama triangle by identifying victims, rescuers, and prosecutors.
Maksym Kunytsia talks about Ideals’ code of conduct for collaboration, which is combined with continuous discovery and continuous delivery.
UX research can feel endless if you’re not asking the right questions. Here’s how focused research questions can streamline your process and deliver insights that matter.