shadcn.io is an independent project built on shadcn/ui
Start Onboarding opens a muted panel with a large icon, the title Welcome aboard, and one line under it. Four dots mark the steps, and the first is filled. Skip and Next sit beside the dots. The last step replaces them with Get Started.
Use it for a short first-run tour people can skip. If a step must point at the real screen, anchor a Popover there. In Solid, Ark UI does not remember that the tour finished.
Installation
Anatomy

Usage
<Dialog onOpenChange={handleOpenChange}>
<DialogTrigger asChild={props => <Button {...props()} variant="outline">Start Onboarding</Button>} />
<DialogContent class="sm:max-w-2xl">
<div class="flex h-64 items-center justify-center rounded-lg bg-muted">
<Dynamic component={step().icon} aria-hidden="true" class="size-24 text-muted-foreground" />
</div>
<DialogHeader class="items-center text-center sm:text-center">
<DialogTitle class="text-2xl">{step().title}</DialogTitle>
<DialogDescription>{step().description}</DialogDescription>
</DialogHeader>
<div class="flex items-center justify-between">
<div aria-hidden="true" class="flex gap-2">
{steps.map((_item, index) => <div class={cn("size-2 rounded-full transition-colors", index === currentStep() ? "bg-foreground" : "bg-muted")} />)}
</div>
<div class="flex gap-4">
{currentStep() < lastStep ? <>
<Button onClick={handleSkip} variant="ghost">
Skip
</Button>
<Button onClick={handleNext}>
Next
<ArrowRightIcon aria-hidden="true" data-icon="inline-end" />
</Button>
</> : <DialogClose asChild={props => <Button {...props()}>
Get Started
<ArrowRightIcon aria-hidden="true" data-icon="inline-end" />
</Button>} />}
</div>
</div>
</DialogContent>
</Dialog>FAQ
How many steps should onboarding have?
Three to five, one idea each. Measure where people drop off and cut the steps nobody needs.
Should people be able to skip?
Always. Skip jumps to the last step here, and the close button and Escape close the dialog at any point.
How do the progress dots work?
They're mapped from the steps, with bg-foreground on the current one and bg-muted on the rest. They're decorative and aria-hidden; the title changes with each step.
Is each step announced?
Each step's title and text are the DialogTitle and DialogDescription, so the dialog is always labelled by the current step.
API Reference
Dialog
Sets onOpenChange={handleOpenChange}, asChild and props. The rest is on the Dialog page.
Button
Sets props, variant="outline", onClick={handleSkip}, variant="ghost" and onClick={handleNext}. The rest is on the Button page.






