VayuUI

useCountdown

A hook to manage countdown timers with start, pause, and reset functionality.

Installation

npx vayu-ui-cli@latest add use-countdown

The useCountdown hook provides a simple way to implement a countdown timer in your React components. It handles the interval logic and state management for you.

Demo

10s

Source Code

Copy this code into src/hooks/useCountdown.ts:

import { useState, useEffect, useRef, useCallback } from 'react';

export interface UseCountdownOptions {
  seconds: number;
  interval?: number;
  onTick?: (timeLeft: number) => void;
  onComplete?: () => void;
  autoStart?: boolean;
}

export const useCountdown = ({
  seconds,
  interval = 1000,
  onTick,
  onComplete,
  autoStart = false,
}: UseCountdownOptions) => {
  const [timeLeft, setTimeLeft] = useState(seconds);
  const [isRunning, setIsRunning] = useState(autoStart);
  const intervalRef = useRef<NodeJS.Timeout | null>(null);

  const onTickRef = useRef(onTick);
  const onCompleteRef = useRef(onComplete);

  useEffect(() => {
    onTickRef.current = onTick;
  }, [onTick]);

  useEffect(() => {
    onCompleteRef.current = onComplete;
  }, [onComplete]);

  useEffect(() => {
    if (!isRunning) return;

    intervalRef.current = setInterval(() => {
      setTimeLeft((prev) => {
        const newTime = prev - 1;
        onTickRef.current?.(newTime);
        if (newTime <= 0) {
          clearInterval(intervalRef.current!);
          setIsRunning(false);
          onCompleteRef.current?.();
        }
        return newTime > 0 ? newTime : 0;
      });
    }, interval);

    return () => {
      if (intervalRef.current) clearInterval(intervalRef.current);
    };
  }, [isRunning, interval]);

  useEffect(() => {
    if (!isRunning) {
      setTimeLeft(seconds);
    }
  }, [seconds, isRunning]);

  const start = useCallback(() => {
    setIsRunning(true);
  }, []);

  const pause = useCallback(() => {
    if (intervalRef.current) clearInterval(intervalRef.current);
    setIsRunning(false);
  }, []);

  const reset = useCallback(() => {
    if (intervalRef.current) clearInterval(intervalRef.current);
    setTimeLeft(seconds);
    setIsRunning(false);
  }, [seconds]);

  return { timeLeft, start, pause, reset, isRunning };
};

Usage

import { useCountdown } from '@/hooks/useCountdown';

const CountdownComponent = () => {
  const { timeLeft, start, pause, reset, isRunning } = useCountdown({
    seconds: 60,
    onComplete: () => alert("Time's up!"),
  });

  return (
    <div>
      <p>Time Left: {timeLeft}s</p>
      <button onClick={start} disabled={isRunning}>
        Start
      </button>
      <button onClick={pause} disabled={!isRunning}>
        Pause
      </button>
      <button onClick={reset}>Reset</button>
    </div>
  );
};

API Reference

Options

PropertyTypeDefaultDescription
secondsnumberRequiredThe initial time in seconds.
intervalnumber1000The interval in milliseconds (default: 1 second).
onTick(timeLeft: number) => voidundefinedCallback function called on every tick.
onComplete() => voidundefinedCallback function called when countdown reaches 0.
autoStartbooleanfalseWhether to start the countdown immediately on mount.

Return Value

PropertyTypeDescription
timeLeftnumberThe current time left in seconds.
start() => voidFunction to start the countdown.
pause() => voidFunction to pause the countdown.
reset() => voidFunction to reset the countdown to original seconds.
isRunningbooleanBoolean indicating if the countdown is active.

On this page