Animated Waitlist Stats

The Waitlist So Far

The room is filling up fast.

Thousands of makers have already claimed a seat. Add yours before the founder pricing window closes.

0+

On the waitlist today

0 countries

Signed up from around the world

0%

Founder discount locked for members

About this block

Animated Waitlist StatsPRO

A centered pre-launch section with a square eyebrow, a heading, a supporting line, a row of accent statistics that count up when scrolled into view, and a dark seal claim-seat button.

ComingSoon45: Animated Waitlist Stats

A centered Polaris pre-launch section with a square eyebrow, a heading, a supporting line, a row of accent statistics that count up when scrolled into view, and a dark seal claim-seat button.

Upgrade to Pro

Pro blocks install through the shadcn CLI with your license key and ship their full source. Docs and live previews stay open to everyone, so you can read every block's details first.

Upgrade Now

Installation

Swap YOUR_EMAIL and YOUR_KEY for the email and license key on your account. Find your license key on your account page.

Radix flavor

bash
npx shadcn add "https://ui.beste.co/r/comingsoon45?email=YOUR_EMAIL&license_key=YOUR_KEY"

Base UI flavor

bash
npx shadcn add "https://ui.beste.co/r-base/comingsoon45?email=YOUR_EMAIL&license_key=YOUR_KEY"

This installs the block to components/beste/block/comingsoon45.tsx.

Quick start

The installed file exports comingsoon45Demo alongside the block: the exact props behind the preview above. Spread it to get a working animated stats section in one line.

tsx
import { ComingSoon45, comingsoon45Demo } from "@/components/beste/block/comingsoon45";

export default function Page() {
  return <ComingSoon45 {...comingsoon45Demo} />;
}

Then replace the demo with your own props. Written out, a trimmed setup looks like this:

tsx
import { ComingSoon45 } from "@/components/beste/block/comingsoon45";

export default function Page() {
  return (
    <ComingSoon45
      label="The Waitlist So Far"
      heading="The room is filling up fast."
      description="Thousands of makers have already claimed a seat."
      button={{ label: "Claim Your Seat", href: "/waitlist" }}
      stats={[
        { value: 8400, suffix: "+", label: "On the waitlist today" },
        { value: 62, suffix: " countries", label: "Signed up worldwide" },
        { value: 40, suffix: "%", label: "Founder discount locked in" },
      ]}
    />
  );
}

Props

PropTypeDefaultDescription
labelstring–Square eyebrow rendered above the heading via Badge6
headingstring–Centered section heading
descriptionstring–Supporting paragraph under the heading
buttonActionLink–Dark seal claim-seat link rendered via Button1
statsStatItem[][]Accent figures that count up when scrolled into view
classNamestring–Extra classes for the outer <section>
ts
type StatItem = {
  value: number;
  suffix?: string;
  prefix?: string;
  label: string;
};

type ActionLink = {
  label: string;
  href: string;
};

Behavior notes

  • An IntersectionObserver at threshold: 0.4 watches the stat row and flips a started flag the first time it scrolls into view, then disconnects, so each figure animates once.
  • Each figure runs a requestAnimationFrame loop with a cubic ease-out over 1400ms to count from zero up to its value, rendering prefix, the running number via toLocaleString("en-US"), and suffix.
  • Because the count begins at zero and only ticks on the client, the figures render as 0 until the observer fires; there is no email form on this block.
  • The stat row renders only when stats is non-empty, and the eyebrow, heading, description, and button each render only when their prop is present.
  • The button renders as a real navigation via Button1 asChild wrapping a Next.js <Link href={button.href} /> with the dark tone, so it points at a URL rather than firing a handler.

More Coming Soon blocks

View all Coming Soon
PRO

comingsoon15

Waitlist Coming Soon

PRO

comingsoon36

Countdown Clock Waitlist

PRO

comingsoon32

Trusted By Waitlist

Get Pro access