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
14 lines
import {
  InformationStep,
  SingleChoiceStep,
  MyCustomComponent,
} from './components'

const componentRegistry = {
  INFORMATION: InformationStep,
  SINGLE_CHOICE: SingleChoiceStep,
  // For custom components, use the payload's `componentKey`
  myCustomKey: MyCustomComponent,
  // You can also map by step id if needed
  welcome: MyCustomComponent, // Maps to step with id 'welcome'
}

Step Component Props

Each step component receives the following props:

typescript
11 lines
interface OnboardingStepComponentProps<TContext = any> {
  step: OnboardingStep<TContext>
  payload: any
  state: EngineState<TContext>
  next: (data?: any) => Promise<void>
  previous: () => Promise<void>
  skip: () => Promise<void>
  goToStep: (id: string | number, data?: any) => Promise<void>
  updateContext: (newContext: Partial<TContext>) => Promise<void>
  setComponentLoading: (isLoading: boolean) => void
}

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


Example: Custom Step Component

tsx
22 lines
type YourPayload = {
  title: string
}

function MyCustomComponent({
  step,
  payload,
  next,
  updateContext,
}: OnboardingStepComponentProps<YourPayload>) {
  const handleSubmit = async () => {
    await updateContext({ answers: { ...payload.answers, custom: true } })
    await next()
  }

  return (
    <div>
      <h2>{payload.title}</h2>
      <button onClick={handleSubmit}>Continue</button>
    </div>
  )
}

Using your Component Registry

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

tsx
38 lines
export default function OnboardingUI() {
  const { state, currentStep } = useOnboarding()

  if (!state) {
    return <Loading />
  }

  if (!currentStep) {
    return (
      <div className="p-10 text-center text-gray-500">
        No active onboarding step.
      </div>
    )
  }
  const componentKey =
    currentStep.payload.componentKey ?? currentStep.id ?? currentStep.type

  const SpecificStepComponent = demoStepComponentRegistry[componentKey]

  if (!SpecificStepComponent) {
    return (
      <div className="flex h-full flex-col items-center justify-center">
        <div className="p-10 text-center text-red-500">
          Error: UI Component not found for step ID ’{currentStep.id}’ (key:{' '}
          {componentKey}).
        </div>
      </div>
    )
  }

  return (
    <SpecificStepComponent
      payload={currentStep.payload}
      coreContext={state.context}
      onDataChange={() => {}}
    />
  )
}

Fallbacks and Error Handling

  • If the current step’s type or componentKey is not found in the registry, you can render a fallback UI.
  • The example above shows a simple error message when the component is not found.
  • 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
const registry = useMemo(
  () => ({
    ...defaultRegistry,
    ...customComponentsFromAPI,
  }),
  [customComponentsFromAPI],
)

Summary

  • Use a component registry to map step types or keys to React components.
  • renderStepContent() 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