Onboarding
First steps, checklists, empty states that teach.
- 5 blocks
- 2 free
- 3 Pro
- Light and dark
- Responsive
Unlock 55 Pro blocks and every template
Every preview is open. With Pro you get the code, copy-paste ready, with every update for good.
Welcome
FreeThree ways to begin, one click each.
onboarding-welcome.tsx
"use client";
import { ArrowRight, Building2, PlayCircle, Upload } from "lucide-react";
import * as React from "react";
import { Button, WaveMark, cn } from "@waveinno/ui";
const CHOICES = [
{ id: "new", icon: <Building2 />, title: "Set up a site", line: "Add your gates and rates. About 10 minutes." },
{ id: "import", icon: <Upload />, title: "Bring your passes", line: "Upload monthly passes from Excel." },
{ id: "tour", icon: <PlayCircle />, title: "Look around first", line: "A sample car park, full of data." },
];
export default function OnboardingWelcome() {
const [pick, setPick] = React.useState("new");
return (
<section className="grid min-h-[560px] place-items-center bg-surface px-4 py-16">
<div className="w-full max-w-2xl text-center">
<WaveMark className="mx-auto size-11" />
<h1 className="disp mt-6 text-[30px] font-bold leading-[1.15] tracking-[-0.03em] text-text">Welcome, Karim</h1>
<p className="mt-2 text-[15px] text-body">How would you like to start?</p>
<div role="radiogroup" aria-label="How to start" className="mt-8 grid gap-3 text-left sm:grid-cols-3">
{CHOICES.map((c) => (
<button
key={c.id}
type="button"
role="radio"
aria-checked={pick === c.id}
onClick={() => setPick(c.id)}
className={cn(
"cursor-pointer rounded-[18px] border-2 bg-raised p-5 transition-[border-color,box-shadow,transform] duration-200 hover:-translate-y-0.5",
pick === c.id ? "border-primary shadow-[0_0_0_4px_var(--primary-subtle)]" : "border-border",
)}
>
<span className={cn("grid size-10 place-items-center rounded-[12px] [&_svg]:size-5", pick === c.id ? "bg-primary text-white" : "bg-hover text-muted")}>{c.icon}</span>
<span className="mt-4 block text-[15px] font-semibold text-text">{c.title}</span>
<span className="mt-1 block text-[13px] leading-[1.5] text-muted">{c.line}</span>
</button>
))}
</div>
<Button variant="primary" size="lg" className="mt-8">
Continue <ArrowRight />
</Button>
<p className="mt-4 text-[13px] text-muted">
<a href="#" className="hover:text-text hover:underline">
Skip for now
</a>
</p>
</div>
</section>
);
}Empty state
FreeA first screen that teaches instead of staying blank.
empty-state.tsx
import { BookOpen, Plus, Ticket, Upload } from "lucide-react";
import { Button } from "@waveinno/ui";
export default function EmptyState() {
return (
<section className="bg-surface px-4 py-12 sm:px-6">
<div className="mx-auto max-w-4xl rounded-[24px] border border-dashed border-border2 bg-raised px-6 py-16 text-center">
{/* Three pass cards fanned out: what this page will hold. */}
<div aria-hidden className="relative mx-auto h-28 w-48">
{[-12, 0, 12].map((r, i) => (
<span
key={r}
className="absolute left-1/2 top-2 h-24 w-36 -translate-x-1/2 rounded-[14px] border border-border bg-surface p-3 text-left shadow-[0_14px_30px_-18px_rgba(5,8,22,.35)]"
style={{ transform: `translateX(-50%) rotate(${r}deg) translateY(${i === 1 ? -6 : 0}px)`, zIndex: i === 1 ? 2 : 1 }}
>
<span className={`grid size-7 place-items-center rounded-[8px] ${i === 1 ? "bg-[linear-gradient(135deg,var(--brand-1),var(--brand-2))] text-white" : "bg-hover text-muted"}`}>
<Ticket className="size-3.5" />
</span>
<span className="mt-3 block h-1.5 w-20 rounded-full bg-border2" />
<span className="mt-1.5 block h-1.5 w-12 rounded-full bg-border" />
</span>
))}
</div>
<h2 className="disp mt-8 text-[22px] font-bold leading-8 text-text">No monthly passes yet</h2>
<p className="mx-auto mt-2 max-w-md text-[14.5px] leading-[1.6] text-muted">Passes let tenants and staff park without a ticket. The gate reads the plate and lets them through.</p>
<div className="mt-7 flex flex-wrap justify-center gap-3">
<Button variant="primary">
<Plus /> Add a pass
</Button>
<Button variant="secondary">
<Upload /> Import from Excel
</Button>
</div>
<a href="#" className="mt-6 inline-flex items-center gap-1.5 text-[13px] font-medium text-primary hover:underline">
<BookOpen className="size-4" /> How passes work
</a>
</div>
</section>
);
}Steps with progress and the next action.
Set-up wizard
ProYour site, your gates, your rates, step by step.
Product tour
ProA spotlight and a coach mark on the real screen.