Onboarding

PreviousNext

Composable multi-step onboarding primitives with feature carousel, choice group radio selector, tips list, and step indicator.

Installation

pnpm dlx shadcn@latest add https://cult-ui.com/r/onboarding.json

Usage

import { Onboarding, FeatureCarousel, ChoiceGroup, TipsList, useOnboarding, } from "@/components/ui/onboarding"
<Onboarding totalSteps={3} onComplete={() => console.log("done")}> <Onboarding.StepIndicator /> <Onboarding.Step step={1}> <Onboarding.Header title="Welcome" description="Here's what you can do" /> </Onboarding.Step> <Onboarding.Step step={2}> <Onboarding.Header title="Personalize" description="Choose your role" /> <ChoiceGroup name="role" onValueChange={(v) => setRole(v)}> <ChoiceGroup.Item value="designer">Designer</ChoiceGroup.Item> <ChoiceGroup.Item value="developer">Developer</ChoiceGroup.Item> </ChoiceGroup> </Onboarding.Step> <Onboarding.Step step={3}> <Onboarding.Header title="You're ready!" description="A few tips" /> <TipsList title="Tips"> <TipsList.Item number={1}>Be specific with your prompts.</TipsList.Item> </TipsList> </Onboarding.Step> <Onboarding.Navigation completeLabel="Get Started" /> </Onboarding>

Components

Onboarding (Root)

The root component manages step state and provides context to all children.

PropTypeDefaultDescription
totalStepsnumberTotal number of steps (required)
valuenumberControlled current step (1-based)
defaultValuenumber1Default step for uncontrolled usage
onValueChange(step: number) => voidCallback when step changes
maxStepValuenumber0Max sub-step index for step 1 (e.g. feature carousel)
canGoNext(step, stepValue) => boolean() => trueCustom gate for proceeding
onComplete() => voidCalled when the last step is completed

Onboarding.Step

Renders children only when its step matches the current step.

PropTypeDescription
stepnumberStep index (1-based)

Onboarding.Header

Renders a centered title and description with serif font styling.

PropTypeDescription
titlestringStep title
descriptionstringStep description
childrenReactNodeCustom content (overrides title/description)

Onboarding.Navigation

Default navigation with Back and Next/Complete buttons.

PropTypeDefaultDescription
backLabelstring"Back"Back button label
nextLabelstring"Next"Next button label
completeLabelstring"Start Creating"Complete button label
canGoNextbooleanOverride next gate from context
childrenReactNodeCustom navigation content

Onboarding.StepIndicator

Connects to onboarding context and renders a StepIndicator.

PropTypeDefaultDescription
variant"dots" | "pills""dots"Visual style of the indicators
dotClassNamestringExtra class for each step dot

FeatureCarousel

Tablist-style feature selector that syncs with stepValue in the onboarding context.

PropTypeDefaultDescription
valuenumberControlled active index
defaultValuenumber0Default active index
onValueChange(index: number) => voidCallback on change
totalItemsnumberTotal items (derived from children if omitted)

FeatureCarousel.Item

PropTypeDescription
indexnumberIndex of this item (0-based)

ChoiceGroup

Accessible radio group for single-select choices.

PropTypeDefaultDescription
namestringRadio group name (required for a11y)
valuestring | nullControlled selected value
defaultValuestring | nullnullDefault selected value
onValueChange(value: string) => voidCallback on selection
orientation"horizontal" | "vertical" | "grid""grid"Layout orientation

ChoiceGroup.Item

PropTypeDescription
valuestringValue when this item is selected

TipsList

Ordered tips list with optional visible title.

PropTypeDescription
titlestringOptional label (screen-reader only by default)

TipsList.Item

PropTypeDescription
numbernumberOptional step number shown inline

Controlled Usage

const [step, setStep] = useState(1) <Onboarding value={step} onValueChange={setStep} totalSteps={3} canGoNext={(s) => s !== 2 || roleSelected} onComplete={handleComplete} > {/* steps */} </Onboarding>

Pair maxStepValue on the root with a FeatureCarousel synced via stepValue to let users page through features before advancing:

const FEATURES = ["Generate", "Ideas", "Upload"] <Onboarding totalSteps={3} maxStepValue={FEATURES.length - 1}> <Onboarding.Step step={1}> {({ stepValue, setStepValue }) => ( <FeatureCarousel value={stepValue} onValueChange={setStepValue} totalItems={FEATURES.length} > {FEATURES.map((f, i) => ( <FeatureCarousel.Item key={f} index={i}> {f} </FeatureCarousel.Item> ))} </FeatureCarousel> )} </Onboarding.Step> </Onboarding>