Next.js

Using OnboardJS in a Next.js Project

OnboardJS integrates smoothly with both the App Router (app/ directory) and the Pages Router (pages/ directory) in Next.js projects. This overview explains how to set up OnboardJS in either structure, with best practices for state management, persistence, and SSR considerations.


Installation

Install the React SDK and core engine:

bash
1 lines
1npm install @onboardjs/react @onboardjs/core

Using OnboardJS with the App Router (app/ Directory)

The App Router uses React Server Components by default, but OnboardJS should be used in Client Components only.

Basic Setup

  1. Create your steps configuration (e.g., onboardingSteps.ts):

    tsx
    19 lines
    1// app/onboardingSteps.ts
    2export const steps = [
    3  {
    4    id: 'welcome',
    5    type: 'INFORMATION',
    6    payload: { title: 'Welcome!' },
    7    nextStep: 'profile',
    8  },
    9  {
    10    id: 'profile',
    11    type: 'SINGLE_CHOICE',
    12    payload: {
    13      question: 'Your role?',
    14      options: [{ id: 'dev', label: 'Developer', value: 'dev' }],
    15    },
    16    nextStep: 'done',
    17  },
    18  { id: 'done', type: 'INFORMATION', payload: { title: 'All set!' } },
    19]
    
  2. Create a client onboarding UI component:

    tsx
    37 lines
    1// app/onboarding/OnboardingUI.tsx
    2'use client'
    3
    4import { useOnboarding } from '@onboardjs/react'
    5
    6export function OnboardingUI() {
    7  const { currentStep, state, next, previous } = useOnboarding()
    8
    9  if (state.isCompleted) return <div>Onboarding complete!</div>
    10
    11  const Component =
    12    yourComponentRegistry[
    13      currentStep.payload.componentKey ?? currentStep.type ?? currentStep.id
    14    ]
    15
    16  if (!Component) {
    17    return <div>Unknown step</div>
    18  }
    19
    20  return (
    21    <div>
    22      <Component
    23        payload={currentStep.payload}
    24        coreContext={state.context}
    25        onDataChange={() => {}}
    26      />
    27      <div>
    28        <button onClick={previous} disabled={!state.canGoPrevious}>
    29          Back
    30        </button>
    31        <button onClick={next} disabled={!state.canGoNext}>
    32          Next
    33        </button>
    34      </div>
    35    </div>
    36  )
    37}
    
  3. Wrap your UI with OnboardingProvider in a client component:

    tsx
    17 lines
    1// app/onboarding/page.tsx
    2'use client'
    3
    4import { OnboardingProvider } from '@onboardjs/react'
    5import { steps } from '../onboardingSteps'
    6import { OnboardingUI } from './OnboardingUI'
    7
    8export default function OnboardingPage() {
    9  return (
    10    <OnboardingProvider
    11      steps={steps}
    12      localStoragePersistence={{ key: 'onboardjs:my-flow' }}
    13    >
    14      <OnboardingUI />
    15    </OnboardingProvider>
    16  )
    17}
    

Tips:

  • Always use 'use client' at the top of any file that uses OnboardJS hooks or context.
  • You can place the provider at any level (e.g., in a layout or a specific page).

Using OnboardJS with the Pages Router (pages/ Directory)

The Pages Router uses classic React components and works seamlessly with OnboardJS.

Basic Setup

  1. Create your steps configuration (e.g., onboardingSteps.ts):

    tsx
    19 lines
    1// pages/onboardingSteps.ts
    2export const steps = [
    3  {
    4    id: 'welcome',
    5    type: 'INFORMATION',
    6    payload: { title: 'Welcome!' },
    7    nextStep: 'profile',
    8  },
    9  {
    10    id: 'profile',
    11    type: 'SINGLE_CHOICE',
    12    payload: {
    13      question: 'Your role?',
    14      options: [{ id: 'dev', label: 'Developer', value: 'dev' }],
    15    },
    16    nextStep: 'done',
    17  },
    18  { id: 'done', type: 'INFORMATION', payload: { title: 'All set!' } },
    19]
    
  2. Create your onboarding UI component:

    tsx
    35 lines
    1// pages/onboarding/OnboardingUI.tsx
    2import { useOnboarding } from '@onboardjs/react'
    3
    4export function OnboardingUI() {
    5  const { currentStep, state, next, previous } = useOnboarding()
    6
    7  if (state.isCompleted) return <div>Onboarding complete!</div>
    8
    9  const Component =
    10    yourComponentRegistry[
    11      currentStep.payload.componentKey ?? currentStep.type ?? currentStep.id
    12    ]
    13
    14  if (!Component) {
    15    return <div>Unknown step</div>
    16  }
    17
    18  return (
    19    <div>
    20      <Component
    21        payload={currentStep.payload}
    22        coreContext={state.context}
    23        onDataChange={() => {}}
    24      />
    25      <div>
    26        <button onClick={previous} disabled={!state.canGoPrevious}>
    27          Back
    28        </button>
    29        <button onClick={next} disabled={!state.canGoNext}>
    30          Next
    31        </button>
    32      </div>
    33    </div>
    34  )
    35}
    
  3. Wrap your UI with OnboardingProvider in your page component:

    tsx
    15 lines
    1// pages/onboarding/index.tsx
    2import { OnboardingProvider } from '@onboardjs/react'
    3import { steps } from '../onboardingSteps'
    4import { OnboardingUI } from './OnboardingUI'
    5
    6export default function OnboardingPage() {
    7  return (
    8    <OnboardingProvider
    9      steps={steps}
    10      localStoragePersistence={{ key: 'onboardjs:my-flow' }}
    11    >
    12      <OnboardingUI />
    13    </OnboardingProvider>
    14  )
    15}
    

Persistence and SSR Considerations

  • Persistence:
    Use the localStoragePersistence prop for client-side persistence, or provide custom handlers for backend persistence (e.g., Supabase, Neon).
  • SSR:
    OnboardJS is designed for client-side onboarding flows. Do not use OnboardJS hooks or context in server components or getServerSideProps.
  • Hydration:
    If you need to pre-populate onboarding context from the server, pass it as initialContext to the provider.

Advanced: Custom Step Components and Dynamic Flows

  • Use a componentRegistry map to map step types or keys to your own React components.
  • You can generate steps dynamically based on user data or API responses before rendering the provider.

Example: Integrating with Supabase in Next.js

tsx
36 lines
1// app/onboarding/page.tsx or pages/onboarding/index.tsx
2'use client';
3
4import { OnboardingProvider } from '@onboardjs/react';
5import { steps } from '../onboardingSteps';
6import { OnboardingUI } from './OnboardingUI';
7import { supabase } from '../lib/supabaseClient';
8
9export default function OnboardingPage() {
10  return (
11    <OnboardingProvider
12      steps={steps}
13      customOnDataLoad={async () => {
14        const { data } = await supabase
15          .from('onboarding')
16          .select('context')
17          .eq('user_id', /* your user id */)
18          .single();
19        return data?.context || undefined;
20      }}
21      customOnDataPersist={async (context) => {
22        await supabase
23          .from('onboarding')
24          .upsert({ user_id: /* your user id */, context });
25      }}
26      customOnClearPersistedData={async () => {
27        await supabase
28          .from('onboarding')
29          .delete()
30          .eq('user_id', /* your user id */);
31      }}
32    >
33      <OnboardingUI />
34    </OnboardingProvider>
35  );
36}

Summary

  • OnboardJS works with both the App Router and Pages Router in Next.js.
  • Always use OnboardJS in client components.
  • Wrap your onboarding UI with OnboardingProvider and use the useOnboarding hook for state and actions.
  • Use localStorage or custom persistence as needed.
  • For advanced flows, leverage the component registry and dynamic step generation.

For more, see the Quickstart Guide and React SDK Overview.

Previous
Examples & Recipes