Stop Reinventing the Onboarding Wheel. Start Building.

Your users need smooth flows. You need clean code, faster. OnboardJS handles the messy state stuff so that you can focus on building.

WelcomeStep.tsx
stepsConfig.ts
function WelcomeStep() {
const { next } = useOnboarding()
return (
<div>
<button onClick={next}>Next</button>
</div>
)
}

Core concepts

Onboarding Context

The Onboarding Context is the dynamic state object that OnboardJS uses to track everything about a user's progress through your onboarding flow. It is passed to step conditions, navigation functions, and lifecycle hooks, and is available throughout your UI via the React SDK.


What is the Onboarding Context?

The onboarding context is a TypeScript object that persists throughout the lifecycle of an onboarding flow. It is:

  • Mutable: Steps and your application can update it as the user progresses.
  • Extensible: You define its shape to fit your product's needs.
  • Flow-aware: It always contains a special flowData property, which tracks internal onboarding state.

The context is passed to step conditions, event handlers, and is available in your UI via the React SDK.

Using flowData

flowData is your main scratchpad for storing:

  • Answers to questions (e.g., user role, preferences)
  • Progress flags (e.g., hasCompletedProfile)
  • Data for conditional logic (e.g., which steps to show next)
  • Any other onboarding-related state

Example:

tsx
10 lines
1// After a SINGLE_CHOICE step:
2context.flowData.userRole = 'developer'
3
4// After a checklist step:
5context.flowData.completedTasks = ['profile', 'settings']
6
7// For conditional navigation:
8if (context.flowData.userRole === 'admin') {
9  // Show admin-specific steps
10}

Extending the Context

You can add your own properties to the context for your app’s needs. For example:

tsx
12 lines
1interface MyAppOnboardingContext extends OnboardingContext {
2  version: string // Onboarding version
3  flowData: {
4    userRole?: string // e.g., "developer", "designer"
5    hasCompletedProfile?: boolean
6    newsletterOptIn?: boolean
7    completedTasks?: string[] // e.g., ["profile", "settings"]
8    [key: string]: any // Allow additional custom properties
9  }
10  user?: { id: string; name: string }
11  appSettings?: { theme: string }
12}

Then, use this type in your onboarding config and steps for better type safety.

How is the Context Updated?

You can update the context at any time using the engine's API.

typescript
1 lines
1await engine.updateContext({ flowData: { preferences: { theme: 'light' } } })

Updating the flow data is additive, meaning you can specify only the new data you want to merge into the existing context and the previous values will be preserved.

typescript
5 lines
1await engine.updateContext({ flowData: { answers: { q1: 'foo' } } })
2await engine.updateContext({ flowData: { answers: { q2: 'bar' } } }) // This WILL NOT overwrite q1
3
4await engine.updateContext({ flowData: { preferences: { theme: 'light' } } })
5await engine.updateContext({ flowData: { preferences: { theme: 'dark' } } }) // This WILL overwrite the previous value of `theme`

Or in React:

tsx
2 lines
1const { updateContext } = useOnboarding()
2updateContext({ flowData: { answers: { q1: 'yes' } } })

Accessing the Context

From the Engine:

tsx
2 lines
1const state = engine.getState()
2console.log(state.context.currentUser)

From React:

tsx
2 lines
1const { state } = useOnboarding()
2<div>Welcome, {state.context.currentUser.name}!</div>

Using Context in Step Logic

You can use the context in:

  • condition functions to show/hide steps
  • nextStep/previousStep functions for dynamic navigation
  • onStepActive and onStepComplete hooks for side effects

Example:

tsx
8 lines
1{
2  id: 'choose-theme',
3  type: 'SINGLE_CHOICE',
4  payload: { ... },
5  condition: (context) => context.currentUser != null,
6  nextStep: (context) =>
7    context.preferences.theme === 'dark' ? 'dark-intro' : 'light-intro',
8}

Best Practices

  • Avoid mutating flowData directly: Let the engine manage it.
  • Keep context serializable: Avoid non-serializable values (functions, class instances) for persistence compatibility.
  • Type your context: For safety and IDE support, always define a custom context interface.

Internal Data

OnboardJS manages some internal state in flowData._internal (like completed steps and timestamps). You usually don’t need to touch this.

Summary

  • The onboarding context is your single source of truth for onboarding state and optionally user data.
  • It is extensible, serializable, and always includes flowData.
  • You can extend the context with your own properties.
  • Use it to drive dynamic flows, persist progress, and personalize onboarding.

Next:

Previous
Typed steps