Product Drop Countdown
A limited-release drop board with a built-in flip countdown, a CTA that unlocks at launch, and a three-state machine ending in a restock notification form once it sells out.
npx shadcn@latest add https://webberui.com/r/product-drop-countdown.jsonPlayground
Tune the props live — the code snippet updates as you go, so you can dial in the look you want before copying it.
<ProductDropCountdown />
Installation
npx shadcn@latest add https://webberui.com/r/product-drop-countdown.jsonOr, once registries are configured in components.json, install it as @webberui/product-drop-countdown.
Usage
import { ProductDropCountdown } from "@/components/ui/product-drop-countdown";
<ProductDropCountdown
title="Aero Runner 3"
subtitle="Limited collab colorway"
price="NT$4,280"
dropAt={Date.now() + 1000 * 60 * 60}
totalStock={180}
onPurchase={() => console.log("add to cart")}
onNotify={(email) => console.log("restock notification", email)}
/>The three states are derived automatically from dropAt and stock: reaching zero on the countdown enters the live state, and selling out of stock enters the sold-out state. To hand control to an outside state machine, pass a controlled state:
<ProductDropCountdown title="Aero Runner 3" dropAt={dropAt} state="soldout" />Stock can be controlled too, driving the depletion bar directly through sold; when it is not provided, depletion is simulated automatically after launch:
<ProductDropCountdown title="Aero Runner 3" dropAt={dropAt} totalStock={200} sold={soldSoFar} />Props
| Prop | Type | Default | Description |
|---|---|---|---|
title | string | — | Product name |
subtitle | string | — | Subtitle / model number and other secondary detail |
price | string | — | Price display string |
dropAt | Date | number | — | Release time; goes live automatically when the countdown reaches zero |
totalStock | number | 200 | Total stock units, driving the depletion bar and the sold-out determination |
sold | number | — | Controlled number sold; when not provided, depletion is simulated automatically after launch |
state | "countdown" | "live" | "soldout" | — | Controlled three states; when provided, the automatic derivation is ignored |
ctaLabel | string | "Buy now" | Copy on the purchase CTA |
onDrop | () => void | — | Fires once on entering the live state |
onSoldOut | () => void | — | Fires once on selling out |
onPurchase | () => void | — | Fires when the purchase CTA is clicked |
onNotify | (email: string) => void | — | Fires when the restock notification form is submitted |
How it works
- Flip clock: every digit is its own flip card; when the value changes, the front leaf falls down around its bottom edge while the back leaf flips back around its top edge, implemented with CSS 3D
rotateXand updated frame by frame. - Launch unlock: the moment the countdown reaches zero, the locked CTA springs in and scales up on an elastic spring (
stiffness: 440, damping: 12), and the stock depletion bar starts at the same time, turning amber and then red as the remaining proportion drops below 50% and 20%. - Sold-out desaturation: once stock hits zero, the whole section is desaturated with a
grayscalefilter and its opacity is lowered, and the restock notification form slides in from below; the form itself stays in full color so it remains readable and usable.
Accessibility
- The countdown carries
role="timer"and a readablearia-label(for example "1 hour 0 minutes 12 seconds until release"), while the flip digits are hidden from assistive technology (aria-hidden). - Remaining stock is announced through
aria-live="polite", so screen readers pick up the changes in the live state. - The restock form's input carries a
labeland anaria-labeland can be submitted with Enter; the CTA and the submit button both havefocus-visibleoutlines. - When the user has "reduce motion" enabled at the system level, the flip switches directly, the CTA and the form fade in instead, and the desaturation completes instantly — none of which affects the three-state logic.
Anchored Buy Rail
An anchored buy rail — a long-scrolling left column beside a sticky buy panel that FLIPs down into a mini checkout capsule as you scroll, then expands again as the reviews section comes near.
Receipt Cart
A shopping cart built on the thermal-receipt metaphor — line items print in one row at a time, the perforated paper edge extends, the subtotal and free-shipping progress at the tail roll to their new values, and removing a row strikes it through and tears it out.