Time left until a moment, ticking each second, with unit names in the reader's language.
$ pnpm dlx shadcn@latest add @dashral/countdownInstallation
$ pnpm dlx shadcn@latest add @dashral/countdownAdds the component, the components it builds on, its npm packages and the theme tokens it uses. Or by its full URL: https://dashral.com/r/countdown.json
Usage
import { Countdown } from "@/components/dashral/countdown"
<Countdown to="2026-12-01T09:00:00Z" onComplete={() => router.refresh()} />Using the npm package? Import from @dashral/ui/components/countdown instead, here and in the examples; the rest is the same.
Examples
API reference
Countdown
Also takes every prop of <div>(opens in a new tab).
| Prop | Type | Default |
|---|---|---|
to | Date | string | numberWhen it ends. Required. | — |
units | ("days" | "hours" | "minutes" | "seconds")[]Which to show; the largest takes what's above it (no days: 50 hours). | all four |
variant | "boxes" | "inline"Each number in a box with its unit, or one line: "2d 04:15:09". | "boxes" |
size | "sm" | "default" | "lg"Its size. | "default" |
onComplete | () => voidCalled once at zero, or right away if | — |
completed | ReactNodeShown in place of the numbers once it's over. | — |
classNames | { unit, value, label }Classes for each part. | — |
className | stringExtra classes, merged with cn() so yours win. | — |
Accessibility
- role="timer", named by the whole time left ("3 days, 5 hours, 42 minutes, 9 seconds"); a timer isn't announced on every tick.
- Unit names come from the browser's Intl in the page's locale, plurals included, so they need no translation.
- The numbers fill in once it's in the browser, so the server never shows a time that's already wrong.
Motion
- Only the digits that change roll: the old one slides down and fades out as the new one slides in from above, in the same cell (--duration-considered). With reduced motion they change in place.