Join our Discord Community

useCountdown

React hook that manages countdown functionality with configurable intervals, increment/decrement modes, and start/stop/reset controls.

Loading component...

Installation

npx shadcn@latest add https://www.shadcn.io/registry/use-countdown.json
npx shadcn@latest add https://www.shadcn.io/registry/use-countdown.json
pnpm dlx shadcn@latest add https://www.shadcn.io/registry/use-countdown.json
bunx shadcn@latest add https://www.shadcn.io/registry/use-countdown.json

Features

  • Flexible direction - Count down or count up with isIncrement option
  • Configurable interval - Set custom intervals in milliseconds
  • Auto-stop - Automatically stops when reaching the target value
  • Full control - Start, stop, and reset functionality
  • Custom boundaries - Set custom start and stop values
  • Performance optimized - Uses efficient interval management

Usage

import { useCountdown } from "@/hooks/use-countdown"

function Timer() {
  const [count, { startCountdown, stopCountdown, resetCountdown }] = useCountdown({
    countStart: 60,
    intervalMs: 1000,
  })

  return (
    <div>
      <div>Time: {count}</div>
      <button onClick={startCountdown}>Start</button>
      <button onClick={stopCountdown}>Stop</button>
      <button onClick={resetCountdown}>Reset</button>
    </div>
  )
}

API Reference

useCountdown

useCountdown(options: CountdownOptions): [number, CountdownControllers]

CountdownOptions

PropertyTypeDefaultDescription
countStartnumber-Starting number for the countdown (required)
countStopnumber0Stopping number (pass -Infinity to decrease forever)
intervalMsnumber1000Interval between updates in milliseconds
isIncrementbooleanfalseWhether to count up instead of down

CountdownControllers

PropertyTypeDescription
startCountdown() => voidStart or resume the countdown
stopCountdown() => voidStop/pause the countdown
resetCountdown() => voidReset to initial value and stop

Return Value

Returns a tuple with:

  • count: Current countdown value
  • controllers: Object with control functions

Usage Examples

Basic Countdown

const [count, { startCountdown, stopCountdown, resetCountdown }] = useCountdown({
  countStart: 30,
})

// Counts down from 30 to 0, stopping automatically at 0

Count Up Timer

const [count, controllers] = useCountdown({
  countStart: 0,
  countStop: 100,
  isIncrement: true,
  intervalMs: 500,
})

// Counts up from 0 to 100, updating every 500ms

Custom Interval

const [fastCount, controllers] = useCountdown({
  countStart: 10,
  intervalMs: 100, // Updates every 100ms for fast countdown
})

Infinite Countdown

const [count, controllers] = useCountdown({
  countStart: 0,
  countStop: -Infinity, // Never stops automatically
  isIncrement: false,
})

// Counts down infinitely (into negative numbers)

Pomodoro Timer

function PomodoroTimer() {
  const [minutes, setMinutes] = useState(25)
  const [seconds, { startCountdown, stopCountdown, resetCountdown }] = useCountdown({
    countStart: minutes * 60,
    intervalMs: 1000,
  })

  const formatTime = (totalSeconds: number) => {
    const mins = Math.floor(totalSeconds / 60)
    const secs = totalSeconds % 60
    return `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`
  }

  useEffect(() => {
    if (seconds === 0) {
      alert("Time's up!")
    }
  }, [seconds])

  return (
    <div>
      <h1>{formatTime(seconds)}</h1>
      <button onClick={startCountdown}>Start</button>
      <button onClick={stopCountdown}>Pause</button>
      <button onClick={resetCountdown}>Reset</button>
    </div>
  )
}

Dynamic Interval

function DynamicTimer() {
  const [interval, setInterval] = useState(1000)
  const [count, controllers] = useCountdown({
    countStart: 60,
    intervalMs: interval,
  })

  return (
    <div>
      <div>Count: {count}</div>
      <input
        type="range"
        min="100"
        max="2000"
        value={interval}
        onChange={e => setInterval(Number(e.target.value))}
      />
      <button onClick={controllers.startCountdown}>Start</button>
    </div>
  )
}

Multiple Timers

function MultiTimer() {
  const [timer1, controls1] = useCountdown({ countStart: 30 })
  const [timer2, controls2] = useCountdown({ 
    countStart: 0, 
    countStop: 60, 
    isIncrement: true 
  })

  return (
    <div>
      <div>Countdown: {timer1}</div>
      <button onClick={controls1.startCountdown}>Start Timer 1</button>
      
      <div>Count Up: {timer2}</div>
      <button onClick={controls2.startCountdown}>Start Timer 2</button>
    </div>
  )
}

Common Use Cases

  • Countdown timers - For games, quizzes, or time-limited activities
  • Pomodoro technique - Work/break interval timers
  • Loading states - Showing progress or timeout countdowns
  • Game mechanics - Cooldowns, respawn timers, round timers
  • Session timeouts - User session expiration warnings
  • Exercise timers - Workout intervals and rest periods
  • Auction timers - Bidding countdown displays
  • Event countdowns - Time until events start

Implementation Details

  • Built on top of useBoolean, useCounter, and useInterval hooks
  • Automatically stops when count reaches countStop
  • Uses useCallback for optimal performance
  • Interval is disabled when countdown is stopped (null passed to useInterval)
  • Reset functionality stops the timer and resets to initial value
  • Supports both increment and decrement modes
  • No memory leaks - intervals are properly cleaned up