React

Rendering Step Content

OnboardJS is headless by design, meaning you have full control over how each onboarding step is rendered. The React SDK makes it easy to map step types or custom keys to your own React components using a component registry.


How Step Rendering Works

  • Each onboarding step has a type (e.g., INFORMATION, SINGLE_CHOICE, CUSTOM_COMPONENT) and may have a payload.componentKey for custom components.
  • You define your component registry, mapping step types, ids or keys to React components.

Defining a Component Registry

A component registry is a plain object mapping step types or custom keys to React components:

tsx
23 lines
1import {
2  IndividualWarning,
3  IndividualCredits,
4  GenerationStep,
5  GenerationSuccessStep,
6  Step1,
7} from './components'
8import { StepComponentProps } from "@onboardjs/react";
9
10export const onboardingStepRegistry: Record<
11  string,
12  (props: StepComponentProps) => JSX.Element
13> = {
14  // Map step IDs to components
15  step1: Step1,
16  "individual-warning": IndividualWarning,
17  "individual-credits": IndividualCredits,
18  // Multiple steps can share the same component
19  "content-creator": GenerationStep,
20  "shop-owner": GenerationStep,
21  "individual": GenerationStep,
22  "generation-success": GenerationSuccessStep,
23};

Step Component Props

Each step component receives the following props:

tsx
11 lines
1interface OnboardingStepComponentProps<TContext = any> {
2  step: OnboardingStep<TContext>
3  payload: any
4  state: EngineState<TContext>
5  next: (data?: Record<string, any>) => Promise<void>
6  previous: () => Promise<void>
7  skip: () => Promise<void>
8  goToStep: (id: string | number, data?: any) => Promise<void>
9  updateContext: (newContext: Partial<TContext>) => Promise<void>
10  setComponentLoading: (isLoading: boolean) => void
11}

This gives your components full access to the current step, onboarding state, and navigation actions.


Example: Custom Step Component

tsx
22 lines
1type YourPayload = {
2  title: string
3}
4
5function MyCustomComponent({
6  step,
7  payload,
8  next,
9  updateContext,
10}: StepComponentProps<YourPayload>) {
11  const handleSubmit = async () => {
12    await updateContext({ answers: { ...payload.answers, custom: true } })
13    await next()
14  }
15
16  return (
17    <div>
18      <h2>{payload.title}</h2>
19      <button onClick={handleSubmit}>Continue</button>
20    </div>
21  )
22}

Using your Component Registry

You can use your component registry with the useOnboarding hook to render the current step:

tsx
19 lines
1export default function OnboardingUI() {
2  const { state, currentStep, renderStep } = useOnboarding()
3
4  if (!state) {
5    return <Loading />
6  }
7
8  if (!currentStep) {
9    return (
10      <div className="p-10 text-center text-gray-500">
11        No active onboarding step.
12      </div>
13    )
14  }
15
16  return <>
17    {renderStep()}
18  </>
19}

Fallbacks and Error Handling

  • If the current step’s type or componentKey is not found in the registry, you can render a fallback UI by checking if renderStep() returns a valid component.
  • You can customize an OnboardingUI component to handle errors gracefully, such as logging or showing a user-friendly message.

Advanced: Dynamic Registries

You can generate the component registry dynamically if your step types or custom components are loaded at runtime.

tsx
7 lines
1const registry = useMemo(
2  () => ({
3    ...defaultRegistry,
4    ...customComponentsFromAPI,
5  }),
6  [customComponentsFromAPI],
7)

Summary

  • Use a component registry to map step types or keys to React components.
  • renderStep() automatically renders the correct component for the current step.
  • Step components receive full context and navigation actions as props.
  • Customize your onboarding UI freely—OnboardJS handles the logic, you handle the presentation.

For more, see useOnboarding Hook and Examples & Recipes.

Previous
useOnboarding Hook