Skip to content
shadcn.io

shadcn.io is not affiliated with official shadcn/ui

Centered Countdown Timer Hero Block for React

A compact centred launch hero on solid rails with a live countdown as a full-width band of four cells and an email form whose Shine Button shows its loading and success states.

Framework
UI library

Preview

Preview width

Installation

Part of Pro
Pro unlocks the code and one-line install of every Pro button and text effect, plus the MCP for your AI editor.
Have Pro already? Sign in to open it.Opens here as soon as you're Pro.

Overview

A compact, centred hero for a launch that's on its way, shown here for Tern 1.0, a local-first sync engine. A badge, a headline and a sentence sit above a full-width band of four cells (days, hours, minutes and seconds) that count down live to the 1st of next month: the band has solid rules above and below, + marks on its four corners and hairlines between the digits, which are set at display size. Under it, an email form whose Shine Button walks from Notify me through a spinner to a check, and a line that turns into a confirmation. The hero opens on the page's top rule between the same side rails as the pricing blocks. It's built from Timer, Guides, Shine Button, Field, Input, Badge, Spinner and Status, with CSS transitions for the entrance. For product launches, event countdowns, sale pages, and any campaign with a date to count down to.

FAQ

How do I count down to my own launch date?

Change untilLaunch at the top of the file: it returns the milliseconds left until midnight on the 1st of next month, in the visitor's time zone, so the demo never counts down to a day that's already gone. For a fixed launch, return remainingMsUntilDate(new Date("2027-03-01T17:00:00Z")); the Z makes it the same instant everywhere. Change the badge's "Launching on the 1st" and the headline to match. Once that moment has passed, remainingMsUntilDate returns 0 and there's nothing left to count (a countdown has to start above zero), so render your launched state in place of the Timer from then on.

Why are the digits blank for a moment on load?

The server can't know the visitor's clock, so the countdown starts once the page runs in the browser: the band and its labels render on the server, and the digits fade in as soon as the time is known. That way the page never shows a made-up time first or a mismatch between server and browser. When the countdown reaches zero with the page open, it starts again towards the next 1st.

How do I connect the email form to my mailing list?

The form's request is a stand-in: an effect waits REQUEST_MS while the button shows Joining…, then sets status to "done". Replace that effect with a call to your list provider from submit (new FormData(event.currentTarget).get("email") gives the address), set "done" when it answers, and set "idle" again on an error so the visitor can retry. The browser checks the address before submit runs, because the input is type="email" and required.

What does the visitor see after pressing Notify me?

The Shine Button swaps its label for a spinner and "Joining…", then for a check and "Subscribed", and stays there. The button keeps focus the whole time (it isn't disabled), a second press does nothing, the input turns read-only so the address can't change mid-request, and the line under the form cross-fades from "Join 3,200+ developers on the waitlist" to "You're on the list". Both lines share one grid cell, so the swap never moves the page.

How does a screen reader read the countdown and the form?

The cells are a timer, named with the time left ("12 days 08:34:56"), which screen readers read when they reach it but don't announce every second. The form is named by an sr-only heading, and its input by an sr-only "Email address" label. A status line says "Joining the waitlist…" and then "You're on the waitlist", and the line it replaces is hidden from screen readers while it's invisible. With reduced motion on, the digits and the entrance don't animate.

How does it fit on a phone?

The four cells keep one row down to 320 px: the digits drop from text-6xl to text-4xl and the unit names to 12px, and the hairlines stay. The input and the button stack below the sm breakpoint, the button taking the full width, so the button ends on the first screen.

  • Pro

    Waitlist Signup Hero

    Signup and waitlist

    A compact waitlist hero: the copy beside a card-in-card email form that turns into a confirmation in place, with a closing band of three features coming at launch.

  • Pro

    Centered Launch Badge Hero

    Logos and social proof

    A centered launch-day hero with a rank badge that links to the launch page, a Shine Button and three launch metrics in separate cells whose hairlines overshoot their corners.

  • Pro

    Animated Counter Hero

    Stats and live data

    A compact centered hero for an invoicing app with an announcement pill, a Shine Button and a second action, over a hairline band of four figures that count up when they scroll into view.

  • Pro

    Counter Stats Hero

    Stats and live data

    A compact, start-aligned hero for an email API on solid rails: a headline, a Shine Button and an outline button, then four counters in separate cells whose hairlines overshoot their corners.

  • Pro

    A showcase hero for a keyboard-first issue tracker: a centred headline and two calls to action over a command palette drawn in a hairline frame.

  • Pro

    A compact centered newsletter hero with the email field in a full-width band between two hairlines: a Shine Button subscribes, then a confirmation replaces the form, over a row of subscriber proof.