useCountdown

A countdown hook for deadlines, launches, reservations, and temporary offers. It updates on the next clock-second boundary, returns a display-ready value, and continues tracking elapsed time after a deadline passes.

Last updated August 12, 2026

CreditsModifiedPublished

Copied from initial implementation supplied by a project contributor.

  • Replaced a drifting interval with second-boundary-aligned timeouts.
  • Added invalid-date handling so null and malformed targets safely return null.
  • Changed rounded remaining time to ceiling semantics so a future target does not show zero early.
  • Added documented result types and examples for formatted, segmented, paused, overdue, and RTL countdowns.

Overview

Installation

$ npx shadcn@latest add https://ui.persian-labs.ir/r/use-countdown.json

Usage

Pass an ISO-8601 target date. The returned value is initially null until the hook runs in the browser, which keeps server rendering stable.

import { useCountdown } from "@/hooks/use-countdown"
 
function SaleCountdown({ endsAt }: { endsAt: string }) {
  const countdown = useCountdown(endsAt)
 
  if (!countdown) return null
 
  return (
    <p>
      {countdown.isOverdue
        ? "This offer has ended"
        : "Offer ends in " + countdown.formatted}
    </p>
  )
}

Use a UTC ISO string from your API or database. Passing null or an invalid date disables the timer.

const endsAt = "2026-12-31T23:59:59.000Z"
const countdown = useCountdown(isTimerActive ? endsAt : null)

Examples

Time units

Use the individual units when each part needs its own visual treatment. Hours can exceed 24.

Pause and play

Pause a countdown without losing its remaining duration, then resume it from exactly where it stopped.

Overdue targets

After the target passes, formatted remains absolute while totalSeconds is negative and isOverdue becomes true.

OTP resend

Keep the resend action unavailable until the cooldown expires, then start a fresh countdown whenever another code is sent.

RTL

Keep the time output LTR so separators and digits remain easy to scan inside Persian content.

API Reference

useCountdown(targetIso)

CountdownResult