Countdown
Countdown is a neobrutalist React component from Cruise UI. Days, hours, minutes and seconds in boxes, or one compact line; red in the last minute. Install it with npx shadcn@latest add @cruiseui/countdown.
Install
Terminal
npx shadcn@latest add @cruiseui/countdownFirst time? Installation shows the one-off components.json setup (the @cruiseui registry) and how to turn the theme on.
Example
Corners
Offer ends in
import { CruiseCountdown } from "@/components/cruise/countdown";
export default function CountdownExample() {
// Use target={new Date("2026-12-24T23:59:59")} for a fixed date.
return (
<div className="flex flex-col gap-6">
<CruiseCountdown duration={(2 * 86400 + 5 * 3600 + 14 * 60) * 1000} label="Sale ends in" />
<div className="flex flex-wrap items-center gap-3">
<span>Offer ends in</span>
<CruiseCountdown duration={75 * 1000} compact label="Offer ends in" />
</div>
</div>
);
}
<div role="timer" aria-label="Sale ends in">
<div class="countdown" aria-hidden="true">
<span class="countdown-unit"><span class="countdown-number">02</span><span class="countdown-label">Days</span></span>
<span class="countdown-unit"><span class="countdown-number">05</span><span class="countdown-label">Hours</span></span>
<span class="countdown-unit"><span class="countdown-number">14</span><span class="countdown-label">Min</span></span>
<span class="countdown-unit"><span class="countdown-number">09</span><span class="countdown-label">Sec</span></span>
</div>
<span class="visually-hidden" aria-live="polite">2 days, 5 hours, 14 minutes left.</span>
</div>Needs theme.css. Interactive parts (menus, tabs, drawers) also need the script in the spec for that component.
When to use it
When to use
Sales ending, events starting, game rounds.
When not to
Fake urgency on things that don't end.
Props
CruiseCountdown
| Prop | Type | Default | Description |
|---|---|---|---|
target? | string | number | Date | — | When it ends: a Date, an ISO string or a timestamp. |
duration? | number | — | Or: how long from when it appears, in milliseconds (e.g. a 90-second round). |
onComplete? | (() => void) | — | — |
compact? | boolean | false | One line, "02:14:09", instead of boxes. |
urgent? | boolean | true | Turn --danger in the last minute. |
showDays? | boolean | — | Show the days box (default: when there's at least a day left). |
label? | string | "Time left" | — |
className? | string | — | — |
Accessibility
- role="timer" with a label; the ticking digits are hidden from screen readers.
- It's announced each minute and each of the last 10 seconds, not every second.
- Tabular numbers, so the layout never shifts.