Onboarding Wizard
Onboarding Wizard
Multi-step onboarding flow shown to new users after signup. Located at /onboarding.
How it works
The wizard uses useState<1 | 2>(1) to track the current step. Each step component receives onComplete (advance to next step) and optionally onSkip (advance without completing setup).
function OnboardingPage() {
const [step, setStep] = useState<1 | 2>(1);
return (
<>
{step === 1 && <WelcomeStep onComplete={() => setStep(2)} />}
{step === 2 && <ProfileStep onComplete={() => router.navigate({ to: '/dashboard' })} />}
</>
);
}
Adding a step
- Widen the type:
useState<1 | 2 | 3>(1) - Add a render case:
{step === 2 && <YourStep onComplete={() => setStep(3)} />} - Prefetch data in the route loader if the step needs it:
loader: async ({ context }) => { await ctx.queryClient.ensureQueryData(myQueryOptions); }
Prefetched data means step components can use useQuery without a Suspense boundary.
Step component contract
type StepProps = {
onComplete: () => void;
onSkip?: () => void; // optional: some steps can be skipped
};
onComplete: advance and mark step as doneonSkip: advance without persisting setup (e.g. skip profile photo)
Files
- Route:
src/routes/onboarding.tsx(top-level, outside the_appdashboard shell)
Triggering onboarding
New users are redirected to /onboarding by the _app.tsx layout's beforeLoad when the bootstrap payload's onboardingComplete is false. completeOnboardingFn sets the flag (and invalidates the bootstrap cache) in the final step's onComplete.