Staaarter

Flash Sale Countdown

A flash-sale showcase for a single product: photo, discounted price with the original struck through, a live countdown ticking down from a fixed duration, and a progress bar showing how many units of the limited stock have been claimed. The deal locks itself out once the countdown hits zero.

By Staaarter Team
Ecommerce
Docs
Live preview

Docs

Installation

A real shadcn registry command, not a copy-paste stand-in: it fetches this block plus its button, badge, media-slot dependencies and any missing npm packages, and installs them straight into your project.

npx shadcn add https://staaarter.com/r/flash-sale-countdown.json

Prefer not to use the CLI? Copy the source from the Code toggle above into src/components/blocks/ecommerce/ecommerce17.tsx instead.

Usage

The file also exports ecommerce17Demo, 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 { Ecommerce17, ecommerce17Demo } from "@/components/blocks/ecommerce/ecommerce17";

export default function Page() {
  return <Ecommerce17 {...ecommerce17Demo} />;
}

Props

PropTypeDefaultDescription
badgeLabelstring"Flash Sale"Label on the destructive-variant badge.
productNamestringundefinedProduct name heading.
image{ src: string; alt: string }undefinedProduct photo; falls back to a placeholder when unset.
pricenumbernoneDiscounted price in cents.
originalPricenumbernoneOriginal (pre-discount) price in cents; used both for the strikethrough and the computed discount percentage.
initialSecondsnumbernoneFixed countdown duration in seconds, counted down from the moment the block mounts.
claimednumbernoneUnits already claimed, shown in the progress bar and its label.
totalStocknumbernoneTotal limited-stock units, the denominator for the progress bar.
classNamestringnoneExtra classes for the outer section element.

Behavior notes

  • The countdown is a real ticking timer: a single setInterval started on mount decrements a seconds counter once a second via a functional state update, and the days/hours/minutes/seconds segments shown are derived from that counter at render time, not stored separately.
  • There is no Date.now() or new Date() anywhere in this block; the countdown only ever counts down from the fixed initialSeconds literal passed in, so it behaves identically regardless of when the page is loaded.
  • discountPercent and the stock bar's percentClaimed are both computed inline from price/originalPrice and claimed/totalStock, not stored as separate state.
  • Once the counter reaches 0, the countdown segments are replaced with a 'This deal has ended' message, the discount badge is hidden, and the button becomes disabled and reads 'Deal ended' instead of 'Claim this deal'; the interval also stops rearming itself at that point rather than continuing to tick past zero.
  • The demo's initialSeconds (24,135) starts the countdown at 06:42:15 so a reviewer can watch the seconds segment tick down immediately without waiting for an hour boundary.
  • Claim this deal has no real checkout wiring even while the countdown is running; it's a decorative call to action.