## Onboarding Flow (S—032)

A four-step onboarding form with progress, per-step validation, an async URL check and a finished state.

- URL: https://sundaeui.dev/components/onboarding-flow
- Category: Forms & inputs · Art direction: Refined
- Access: Sundae Pro (authenticated install)
- Stack: React 18+, TypeScript, Tailwind CSS; dependencies: none
- Install: `npx shadcn@latest add https://sundaeui.dev/r/onboarding-flow.json`
- Tags: wizard, tailwind, stepper, form, saas, animated, react, multi-step, onboarding, validation

First-run onboarding that respects people’s time. A segmented progress bar shows the step you’re on and fills half-way while you’re on it. Steps slide in from the direction you’re travelling. Each step validates before moving on, with the error in plain words beside the button.
The workspace URL is derived from the name until you edit it yourself, and is checked asynchronously against taken slugs. Team size is a radio group, goals are multi-select, and invites accept any mix of commas, spaces and newlines, with a live count of valid addresses and a precise error for the bad ones.
Use it as a template for any multi-step form: account setup, applications, configuration wizards. Change STEPS and the step bodies, and keep the navigation and validation.

### Usage

```tsx
import { OnboardingFlow } from '@/components/sundae/onboarding-flow'

<OnboardingFlow
  checkSlug={async (slug) => ((await api.slugTaken(slug)) ? 'That URL is taken.' : null)}
  onFinish={(data) => api.createWorkspace(data)}
/>
```

### Props

- `onFinish` (`(data: OnboardingData) => Promise<void>`, required): Called with { workspace, url, size, goals, invites }. Throw to show an error.
- `checkSlug` (`(slug) => Promise<string | null>`): Returns an error message when the slug is unavailable.

### Accessibility

- Progress is an ordered list with aria-current="step". Each step is a fieldset with a legend.
- Choices use radio and pressed semantics. Errors are announced via role="alert".
- Enter submits the current step, and Back never loses data.
