Pick a working title. You can change it at any point and nothing else depends on it.
Four calm families to start from. Every section you add afterwards speaks the same one.
A hero, a few features and a footer. The agent can draft it from a single sentence.
Draft it nowPoint your domain at the project. Certificates are issued in the background.
Domain settingsEditors see the same pages you do and can publish without asking you.
One click. Every page is rendered, cached and served from the edge.
A setup checklist with a sticky left column: serif headline that settles in word by word, an intro, a large done count over a hairline progress bar that grows as steps are ticked, and a sliding-marker pill. On the right a ruled list of steps, each with a round check button, a serif title that strikes through when done, a description and an optional link.
A checklist that keeps score: round checks you can tick, a count over a hairline that grows as you go, and a line that only appears once every step is done.
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.
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
npx shadcn add "https://ui.beste.co/r/onboarding44?email=YOUR_EMAIL&license_key=YOUR_KEY"Base UI flavor
npx shadcn add "https://ui.beste.co/r-base/onboarding44?email=YOUR_EMAIL&license_key=YOUR_KEY"This installs the block to components/beste/block/onboarding44.tsx plus the button22 sliding-marker pill and the text1 word stagger it uses.
The installed file exports onboarding44Demo alongside the block: the exact props behind the preview above. Spread it to get a working section in one line.
import { Onboarding44, onboarding44Demo } from "@/components/beste/block/onboarding44";
export default function Page() {
return <Onboarding44 {...onboarding44Demo} />;
}Then replace the demo with your own props. Written out, a trimmed setup looks like this:
import { Onboarding44 } from "@/components/beste/block/onboarding44";
export default function Page() {
return (
<Onboarding44
eyebrow="Getting started"
heading="Six small steps to a finished site."
description="Tick them off in any order."
progressLabel="of 6 done"
completeLabel="All set. Your site is ready to publish."
buttons={[{ label: "Open the editor", href: "/editor" }]}
steps={[
{ title: "Name the project", description: "Pick a working title.", done: true },
{ title: "Add a homepage", description: "A hero, a few features and a footer.", link: { label: "Draft it now", href: "/draft" } },
]}
/>
);
}| Prop | Type | Default | Description |
|---|---|---|---|
eyebrow | string | – | Small-caps line above the heading |
heading | string | – | Section heading, through Text1 |
description | string | – | Paragraph under the heading |
progressLabel | string | – | Words after the count, such as of 6 done |
completeLabel | string | – | Line shown only when every step is ticked |
buttons | ActionButton[] | [] | Pill actions under the progress bar |
steps | Step[] | [] | The checklist, in order |
className | string | – | Extra classes for the outer <section> |
type Step = {
title: string;
description: string;
link?: { label: string; href: string };
done?: boolean;
};
type ActionButton = {
label: string;
href: string;
tone?: "primary" | "light" | "dark" | "outline";
};done flag, so the block is interactive out of the box but forgets everything on reload. Lift the state out if you need it to persist.role="checkbox" and aria-checked rather than real inputs, which keeps them keyboard operable without a form around them.scaleX transform on a hairline, so it animates smoothly between any two counts rather than stepping.aria-live region, so a screen reader hears the new total after each tick without being told about the bar.