Sale Countdown Timer
A live sale countdown that genuinely ticks down once a second from a fixed starting duration, in three layouts: a card with large digit tiles, an inline compact bar, or a full-width colored banner. Built to be styled as "time remaining as of page load" rather than a wall-clock deadline.
Docs
Installation
A real shadcn registry command, not a copy-paste stand-in: it fetches this block plus its button dependencies and any missing npm packages, and installs them straight into your project.
npx shadcn add https://staaarter.com/r/sale-countdown-timer.jsonPrefer not to use the CLI? Copy the source from the Code toggle above into src/components/blocks/ecommerce/ecommerce5.tsx instead.
Usage
The file also exports ecommerce5Demo, the exact props behind the preview above. Spread it to get a working section in one line, then replace it with your own data.
import { Ecommerce5, ecommerce5Demo } from "@/components/blocks/ecommerce/ecommerce5"; export default function Page() { return <Ecommerce5 {...ecommerce5Demo} />; }
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| heading | string | "Summer Sale ends soon" | Heading text (or banner message when it hasn't ended). |
| description | string | "Up to 40% off sitewide..." | Supporting copy shown in the default and compact variants. |
| ctaLabel | string | "Shop the sale" | Label for the call-to-action button. |
| ctaHref | string | "#" | Destination for the call-to-action button. |
| initialDuration | CountdownDuration | none | Time remaining as of when the component mounts; the timer counts down from this in memory. |
| variant | "default" | "compact" | "banner" | "default" | Layout: card with large digit tiles, inline compact bar, or full-width colored banner. |
| className | string | none | Extra classes for the outer section element. |
Types
interface CountdownDuration { days: number; hours: number; minutes: number; seconds: number; }
Behavior notes
- The countdown is a real timer: `initialDuration` is converted to a total-seconds count once via a lazy `useState` initializer, then a `setInterval` inside `useEffect` decrements it every second down to zero, it never reads `Date.now()` or constructs a target `Date`, so the server-rendered markup and the client's first tick always agree.
- It stops exactly at zero rather than going negative; the banner variant swaps its message to "This sale has ended." once it does, the default and compact variants show a small "This offer has ended." line instead.
- The `variant` prop is a real, complete layout switch (three different JSX trees), not a CSS-only reskin of the same markup.
- The call-to-action button keeps working after the timer ends, it never disables itself, in a real store you'd conditionally hide or redirect it once the sale is over.
More Ecommerce Blocks
View all →wishlist-manager
Wishlist Manager
Saved-items list with stock-status badges, move-to-cart and remove actions, and a real empty state.
product-information-tabs
Product Information Tabs
Tabbed product details with Description, Features, Specifications, Reviews, and Shipping panels.
collection-showcase-grid
Collection Showcase Grid
A large featured-collection hero card alongside a grid of smaller supporting collection tiles.
shop-by-brand-grid
Shop by Brand Grid
A grid of bordered brand tiles with a wordmark-style name, product count, and a hover affordance.
gift-card-redemption-form
Gift Card Redemption Form
A code-entry form that validates against a fixed list of demo gift cards and shows a real success or error state.
shipping-info-cards
Shipping Info Cards
A row of icon cards covering shipping, delivery, returns, and support promises.