Countdown
A timer that counts down to a set time, with rolling digits.
Usage
Countdown is the timing engine: give it a targetDate (a Date, epoch-ms number, or date
string) or a relative duration in seconds, and it ticks down once per second, breaking the
remaining time into days / hours / minutes / seconds. Each CountdownSegment reads one
of those units from context and renders it as rolling digits — every digit is a 0–9 strip
moved with a GPU transform, so changes slide like an odometer without thrashing layout.
It's intentionally headless: the root is just an inline-flex wrapper and the segments add no
styling of their own — they inherit the font, size, and color from your markup. There are no
built-in labels — you compose "Days/Hours/…" text (and any separators or boxes) yourself, styling
everything through className.
Time zones
Countdown has no timeZone prop, and it doesn't need one. The remaining time is target − now,
a subtraction of two absolute instants (both UTC epoch-milliseconds under the hood), so the
result is a duration — and a duration is the same everywhere. "3 hours left" is 3 hours in every
zone at once, so there is nothing for a time zone to change.
Time zones only matter when you decide which instant targetDate is — and you do that when you
construct it, before the component sees it. Pass an offset-bearing string or a real Date, and the
countdown is identical for every viewer:
Avoid zone-less local strings
A string without an offset — "2027-01-01T00:00:00" — is parsed in each viewer's own time zone, so it points at a
different instant for everyone. Always include an offset (+09:00) or a trailing Z, or compute the instant with a
date-fns time-zone helper and pass the resulting Date.
Examples
Labelled countdown
Wrap each CountdownSegment with your own label and size it however you like. The digits stay
aligned because the segment uses tabular figures.
Relative duration
Pass duration (seconds from mount) instead of targetDate for timers like a flash sale, and use
onComplete to react when it hits zero.
Custom styling
Because every part takes a className (merged via tailwind-merge), you can box each segment, add
separators, or restyle the digits entirely.
Standalone rolling number
CountdownSegment also works on its own — pass a value instead of a unit to animate any number
you drive yourself, no timer required.
RTL
Every Appica UI component supports right-to-left layouts out of the box. Set the dir attribute on a
container (commonly your <html> element) so CSS logical properties resolve correctly, and wrap your
tree in DirectionProvider so direction-aware behavior follows the same direction.
The segments reorder to follow the resolved direction, while the digits themselves keep rolling vertically — numbers read the same in any direction. For setup details and caveats, see the RTL guide.
API reference
Countdown
The timing engine and headless container. Renders a <div role="timer"> and provides the remaining
time to its CountdownSegment children.
Forwards ref, className, aria-*, and any other <div> attributes. Use aria-label to name the
timer (e.g. "Offer ends in").
CountdownSegment
Renders one unit as rolling digits. Use it inside a Countdown with unit, or standalone with value.
Forwards ref, className, and any other <span> attributes. The digit rollers honour
prefers-reduced-motion (snapping instantly instead of sliding).
Accessibility
- The root renders
role="timer"; give it anaria-labeldescribing what it counts down to. - The animated digits are
aria-hidden; each segment also renders ansr-onlyplain-text value so screen readers announce the number (with your adjacent label text). - The timer does not announce on every tick by default (no
aria-live), avoiding once-a-second spam. Addaria-live="polite"to the root yourself if live updates are appropriate. - Digit rolling honours
prefers-reduced-motion— digits update instantly without the slide.