React component reference

Package: @bootstrapware/onboard
Styles: @bootstrapware/onboard/styles.css

Import styles once near the feature. Use a Client Component in Next.js App Router. Bootstrapware does not authenticate checklist end users. Pass user from your session and workspaceKey for shared steps.

Props

PropTypeRequiredNotes
user{ id: string; name?: string }yesOpaque stable id. Never invent this in production. Wire the real session id.
workspaceKeystringshared stepsScopes workspace progress. Bind it on Hosted author tokens when you mint them.
adapterOnboardAdapterBYO / localIf set, progress stays on your adapter (or createLocalAdapter). Hosted config still loads when flowId + publishableKey are also set.
itemsOnboardChecklistItem[]Path ALocal checklist. Hosted/BYO typically load items from published flow config. Optional per-item href and ctaLabel.
configPartial<OnboardFlowConfig>noLocal merge until hosted config loads. Do not put flowId/items here.
flowIdstringHosted / BYO configWith publishableKey. Prefix flw_.
publishableKeystringhosted configBrowser-safe. Never put secret keys in the client.
apiBaseUrlstringnoDefaults to https://onboard.bootstrapware.co
contextOnboardContextnoRole, plan, flags for eligibility. Evaluated in the widget. Never send this through MCP.
factsRecord<string, boolean | "n/a">noSticky reconciliation on mount. true completes; "n/a" hides as inapplicable; false leaves stored progress. Also call completeStep from the host when the user actually does the work.
authorTokenstringlive HostedShort-lived host-signed assertion from POST /api/v1/author-tokens (secret key). Required when the flow sets requireAuthorToken. Live Hosted without a token is test keys only. Your BFF renews it; the widget never mints.
permissionsOnboardTokenPermission[]noDefaults to complete, skip, dismiss, snooze. Include reset (and mint it) to show Reset my progress. Reset is personal scope only.
onEvent(event, payload) => voidBYO side effectsAnalytics / CRM. BYO does not emit Bootstrapware webhooks. Payload carries ids, not host context.
theme"light" | "dark"noOmit for the light cream default. No data-theme and no system theme.
presentation"section" | "modal" | "window" | "launcher"noDefault section (inline). Modal, window, and launcher start closed unless defaultOpen. Escape, the backdrop, or Hide closes modal and launcher. Escape or Hide closes a window.
defaultOpenbooleannoOpen modal, window, or launcher on first render. Ignored for section.
focusedAnchorstringnoSpotlight the item whose anchor matches. Host opt-in; separate from the automatic in-list next-step highlight.
classNamestringnoWrapper class for layout.

Theme

theme is "light" | "dark". Omit it and the checklist stays the light cream default: the root has no data-theme attribute. theme="light" sets data-theme="light" and keeps those light tokens. theme="dark" sets data-theme="dark" and applies the dark shell. v1 does not follow prefers-color-scheme or the system theme.

Hosts may set these CSS custom properties on the embed root (.bsw-ob). These overrides are the supported API. Do not fight .bsw-* classes. When theme="dark" is set, target .bsw-ob[data-theme="dark"] so your values win over the dark defaults.

  • --bsw-ob-bg
  • --bsw-ob-panel
  • --bsw-ob-fg
  • --bsw-ob-muted
  • --bsw-ob-line
  • --bsw-ob-ok
  • --bsw-ob-error
  • --bsw-ob-accent
  • --bsw-ob-accent-fg
  • --bsw-ob-radius
.bsw-ob[data-theme="dark"] {
  --bsw-ob-bg: #161714;
  --bsw-ob-panel: #22241c;
  --bsw-ob-fg: #f4f4ee;
  --bsw-ob-muted: #b3b4aa;
  --bsw-ob-line: #4a4c42;
  --bsw-ob-ok: #8dcea0;
  --bsw-ob-error: #ffb4be;
  --bsw-ob-accent: #c8ef00;
  --bsw-ob-accent-fg: #161714;
  --bsw-ob-radius: 12px;
}

branding.primaryColor, when set, writes --bsw-ob-accent inline on the root and overrides the theme accent. className is for layout, not a second skin.

Next step and item actions

The first incomplete unblocked item is highlighted as the next step in the list. This is separate from focusedAnchor Spotlight, which stays host opt-in.

  • Incomplete unblocked items with href: the primary control is a button-styled link. Label is optional ctaLabel on the item, otherwise Continue. Mark complete is secondary.
  • Items without href: Mark complete stays the primary button.
  • Blocked items show “Complete … first” and no primary CTA.
  • Clicking the href CTA does not mark the step complete. Call completeStep from the host on real actions and pass facts so the widget reconciles on mount.
  • The widget only follows http(s), hash (#…), and relative path hrefs. javascript:, data:, and protocol-relative URLs are ignored (Mark complete stays primary).

Resolve order

  1. Path A — local: createLocalAdapter (or any adapter) plus optional items. Zero keys. Free forever.
  2. Path B — Hosted: omit adapter; pass flowId + publishableKey. Progress lives on Bootstrapware. Live writes need authorToken.
  3. Path C — BYO: pass adapter and flowId + publishableKey so published config still loads. Progress stays on your backend.

Local / demo

import { Onboard, createLocalAdapter, SAAS_FIRST_RUN_ITEMS } from "@bootstrapware/onboard";
import "@bootstrapware/onboard/styles.css";

<Onboard
  user={{ id: session.user.id, name: session.user.name }}
  workspaceKey={workspace.id}
  context={{ role: membership.role, plan: workspace.plan }}
  facts={{ hasBilling: billingConnected }}
  items={SAAS_FIRST_RUN_ITEMS}
  adapter={createLocalAdapter({ storageKey: "demo-onboard" })}
/>

Call completeStep from your app on real actions and pass facts so the widget reconciles on mount. Dismiss hides without 100% progress. Snooze tucks the widget away (default 1 and 7 days).

Hosted

<Onboard
  flowId="flw_..."
  publishableKey={process.env.NEXT_PUBLIC_BSW_ONBOARD_PUBLISHABLE_KEY}
  user={{ id: session.user.id, name: session.user.name }}
  workspaceKey={workspace.id}
  context={{ role: membership.role, plan: workspace.plan }}
  facts={integrationFacts}
  authorToken={authorTokenFromBff}
/>

Live config fetch needs BYO ($9.99) or Hosted ($19.99). Live Hosted writes need Hosted ($19.99). Test publishable keys work unpaid. Auto-renew authorToken from your BFF when expiresAt is within 5 minutes.

Limits in the UI

32 items per flow. 16 eligibility flags per item. See limits.

Related: Configuration · Modes · Adapter · Identity · Facts · Quickstart