Skip to content
EspañolEnglish
All components (204)

Countdown

Dates and time · Countdown · .amset-count

What it is and when to use it

A countdown in seconds: "Resend the code in 29 s", "1:30" from one minute on and "1:02:05" from one hour on, with the digits of the language. For what runs out: resending a code, the end of a reservation, a saved cart.

When to use it

  • A short wait that the person has to see counting down.
  • label says what the countdown is for ("Resend the code") and text changes the sentence shown while it runs.
  • endContent for what appears on reaching zero (normally the button that can now be pressed), finalAnnouncement for what is said then, and onFinish to find out from code.
  • active={false} to stop it where it is (when set back to true it continues from there); when seconds changes it starts over.
  • tone for when time is pressing: warning on a reservation that is about to expire.

When not to

  • Warning that the session is about to expire, with the exits at hand: IdleWarning.
  • A date that has already passed or is yet to come ("3 minutes ago"): RelativeTime.

Keyboard: it is not interactive and does not enter the Tab order; what is placed in endContent does.

Accessibility: the number is seen changing every second, but it is not announced every second, which would drown out anything else the screen reader was reading. A hidden status region says it when the seconds left are a multiple of announceEvery (10 by default), and in words: "Resend the code in 1 minute and 30 seconds", because "1:30" read aloud sounds like a time of day. On reaching zero the same region says finalAnnouncement ("Resend the code: the countdown has finished", by default) and endContent is rendered in place of the countdown. The region is there from the start: one that was born already containing the text might not be read.

Clock: it counts against the real time, not by subtracting one per tick. A background tab receives its timers late (as rarely as once per minute); when you come back, the countdown shows what is really left.

Sizes: font of 12, 13 or 14 px, and it reserves the height of a control of its size (30, 36 or 44 px), so that on reaching zero the endContent button takes the same place and nothing jumps. Give it a button of the same size.

Variants (variant):

  • roll (default): each digit sits in its own window and only the ones that change roll; the outgoing one goes down and the new one comes in from above, like a drum. From 1:30 to 1:29 two digits move, not the whole number.
  • ring: a ring that empties continuously, with no second-by-second jumps, with the number inside and label beside it. It is a single CSS animation that lasts the whole countdown and is driven by the browser's clock; with active={false} it stops where it is. text is not used there.
  • text: the whole number changes at once with a short fade, the look it had before.

Motion: the digits roll at the theme's slow duration and endContent enters with a fade. With reduced motion the digits change without rolling, but the ring keeps emptying at its own pace: it is what remains, not decoration.

Fine-tuning: --amset-count-font, -height (the one it reserves; auto if it goes inside a sentence), -slot, -color (the text), -number-color and -number-weight. In ring, --amset-count-ring (the side: 44, 56 or 72 px depending on the size) and --amset-count-ring-track (the color of what has already been used up); the arc takes the color of the number.

Context: it goes inside LocaleProvider (or AmsetProvider), which decides how the digits are written.

What it looks like

The offer ends in 1 hourYour reservation expires in 1 minute and 30 seconds

{/* Por defecto (roll): ruedan solo las cifras que cambian */}
<Countdown label="The offer ends" seconds={3600} />

{/* Un anillo que se vacia sin saltos, con el numero dentro */}
<Countdown label="Your reservation expires" seconds={90} variant="ring" tone="warning" />

Props

Import it with import { Countdown } from '@amset/ui'. Required props are marked.

PropTypeWhat it does
labelrequiredstringWhat the countdown is for: "Resend the code". Required.
secondsrequirednumber—
activebooleanStarts on its own. With `false` it stays stopped where it is and resumes from there when it goes back to `true`.
announceEverynumberHow many seconds between announcements. Announcing every second is pure noise for whoever uses a screen reader.
classNamestringMerged with the library classes; it does not replace them.
endContentReactNodeWhat is shown on reaching zero, instead of the count: normally a button.
finalAnnouncementstringWhat is announced on reaching zero. By default: "Resend the code: the countdown has finished".
onFinish() => void—
size"sm" | "md" | "lg"Font and reserved height: that of an `sm`, `md` or `lg` control (30, 36 or 44 px).
text(remaining: ReactNode, seconds: number) => ReactNodeWhat is shown while it runs. By default: "Resend the code in 0:29". It receives the number already written, in its own element (the one that moves on change), and the seconds left in case the bare figure is needed.
tone"neutral" | "accent" | "secondary" | "tertiary" | "info" | "success" | "warning" | "error"The color of the text and the number. `neutral` by default; `warning` or `error` when something that matters is running out.
variantCountdownVariantHow it looks: `roll` (the default, the digits roll), `ring` (a ring that empties, with the number inside and `label` beside it; `text` is not used there) or `text` (the whole number jumps, as before).

It also accepts the attributes of the element it renders: className, style, data-*, aria-* and its events.

CSS variables

These CSS variables are how you adapt it. Declare them on the component's selector, not on :root: the stylesheet redeclares them in the rule itself, and a declaration on the same element always wins.

VariableDefault
--amset-count-colorvar(--amset-ink-2)
--amset-count-number-colorvar(--amset-ink)
--amset-count-number-weightvar(--amset-weight-medium)
--amset-count-fontvar(--amset-text-sm)
--amset-count-heightvar(--amset-height-control)
--amset-count-slotvar(--amset-space-2)

How to change it

.amset-count {
  --amset-count-color: ...;
  --amset-count-number-color: ...;
}

In the test bench

Every state and variant, to try one at a time, on its page at ui.amset.tech: