onboardjs-react について
onboardjs-react は、OnboardJS でオンボーディングフローを構築するための React 統合ガイドです。独自 UI を作り、フロー状態やナビゲーションをライブラリに任せたい開発者向けです。
主な機能
- 01React プロジェクトとパッケージマネージャーの検出
- 02ステップコンポーネントと Provider の設定
- 03描画とナビゲーション用のフック
- 04ステップ ID による進捗管理
- 05Next.js のクライアント設定と遅延読み込み
- 06ローカルおよび独自バックエンドへの永続化
活用シーン
- 01React アプリへのオンボーディング追加
- 02オンボーディング設定の Next.js 対応
- 03ステップ進捗の追跡
- 04ローカル保存または API による状態保存
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ onboardjs/ onboardjs-skills --skill onboardjs-reactインストール後、Claude Code で/onboardjs-reactを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/hooks-api.mdpatterns.mdstep-config.md詳細
OnboardJS React 統合
OnboardJS は、ユーザーのオンボーディング体験を構築するためのヘッドレスライブラリです。UI はご自身で制御し、OnboardJS がフローのロジック、状態、永続化、ナビゲーションを処理します。
開始する前に
1. React プロジェクトを確認する - React の依存関係が含まれる package.json があるか確認します。React プロジェクトでない場合は、ユーザーにその旨を伝えてください。
2. パッケージマネージャーを検出する - ロックファイルを確認し、適切なインストールコマンドを判断します:
| ロックファイル | パッケージマネージャー | インストールコマンド |
|---|---|---|
pnpm-lock.yaml | pnpm | pnpm add @onboardjs/core @onboardjs/react |
yarn.lock | yarn | yarn add @onboardjs/core @onboardjs/react |
bun.lockb | bun | bun add @onboardjs/core @onboardjs/react |
package-lock.json またはなし | npm | npm install @onboardjs/core @onboardjs/react |
3. Next.js を検出する - next.config.js、next.config.mjs、または依存関係に next が含まれているか確認します。Next.js の場合は、Next.js のセットアップ セクションを参照してください。
インストール
# npm
npm install @onboardjs/core @onboardjs/react
# pnpm
pnpm add @onboardjs/core @onboardjs/react
# yarn
yarn add @onboardjs/core @onboardjs/react
# bun
bun add @onboardjs/core @onboardjs/react
クイックセットアップ
1. コンポーネントでステップを定義する
// steps.tsx
import { OnboardingStep } from '@onboardjs/react'
import { WelcomeStep } from './components/WelcomeStep'
import { ProfileFormStep } from './components/ProfileFormStep'
import { CompleteStep } from './components/CompleteStep'
const steps: OnboardingStep[] = [
{
id: 'welcome',
component: WelcomeStep,
payload: { title: 'Welcome!', description: 'Let\'s get started' },
nextStep: 'profile'
},
{
id: 'profile',
component: ProfileFormStep,
nextStep: 'complete'
},
{
id: 'complete',
component: CompleteStep,
payload: { title: 'All done!' },
nextStep: null
}
]
2. プロバイダーでラップする
import { OnboardingProvider } from '@onboardjs/react'
import { steps } from './steps'
function App() {
return (
<OnboardingProvider
steps={steps}
onFlowComplete={(ctx) => console.log('Done!', ctx)}
>
<OnboardingUI />
</OnboardingProvider>
)
}
3. フックを使用する
import { useOnboarding } from '@onboardjs/react'
function OnboardingUI() {
const { renderStep, next, previous, state, loading } = useOnboarding()
if (loading.isHydrating) return <Spinner />
if (state?.isCompleted) return <CompletedScreen />
return (
<div>
{renderStep()}
<div>
<button onClick={previous} disabled={state?.isFirstStep}>Back</button>
<button onClick={() => next()} disabled={!state?.canGoNext}>
{state?.isLastStep ? 'Finish' : 'Next'}
</button>
</div>
</div>
)
}
ステップインジケーター/進捗状況
重要: state オブジェクトには steps 配列がありません。currentStepNumber と totalSteps を使うか、ステップ ID から計算してください。
オプション 1:組み込みプロパティを使用する(利用可能な場合)
function OnboardingUI() {
const { state, renderStep } = useOnboarding()
return (
<div>
{state?.currentStepNumber && state?.totalSteps && (
<div>Step {state.currentStepNumber} of {state.totalSteps}</div>
)}
<progress
value={state?.currentStepNumber ?? 0}
max={state?.totalSteps ?? 1}
/>
{renderStep()}
</div>
)
}
オプション 2:ステップ ID から計算する(推奨)
進捗状況を確実に追跡するには、ステップ ID を一度だけ定義してインデックスを計算します:
// steps.tsx - export your step IDs
export const STEP_IDS = ['welcome', 'profile', 'preferences', 'complete'] as const
export const steps: OnboardingStep[] = [
{ id: 'welcome', component: WelcomeStep, nextStep: 'profile' },
{ id: 'profile', component: ProfileStep, nextStep: 'preferences' },
{ id: 'preferences', component: PreferencesStep, nextStep: 'complete' },
{ id: 'complete', component: CompleteStep, nextStep: null }
]
// OnboardingUI.tsx
import { STEP_IDS } from './steps'
function OnboardingUI() {
const { state, renderStep } = useOnboarding()
const currentIndex = STEP_IDS.findIndex(id => id === state?.currentStep?.id)
const currentStepNumber = currentIndex + 1
const totalSteps = STEP_IDS.length
return (
<div>
<div>Step {currentStepNumber} of {totalSteps}</div>
<progress value={currentStepNumber} max={totalSteps} />
{renderStep()}
</div>
)
}
ステップインジケーターコンポーネント
interface StepIndicatorProps {
stepIds: readonly string[]
currentStepId: string | undefined
}
function StepIndicator({ stepIds, currentStepId }: StepIndicatorProps) {
const currentIndex = stepIds.findIndex(id => id === currentStepId)
return (
<div className="flex gap-2">
{stepIds.map((id, index) => (
<div
key={id}
className={`w-3 h-3 rounded-full ${
index < currentIndex ? 'bg-green-500' :
index === currentIndex ? 'bg-blue-500' :
'bg-gray-300'
}`}
/>
))}
</div>
)
}
// Usage
<StepIndicator stepIds={STEP_IDS} currentStepId={state?.currentStep?.id} />
ステップコンポーネントのパターン
import { StepComponentProps } from '@onboardjs/react'
interface ProfilePayload {
title: string
fields: string[]
}
const ProfileFormStep: React.FC<StepComponentProps<ProfilePayload>> = ({
payload,
context,
onDataChange,
initialData
}) => {
const [name, setName] = useState(initialData?.name || '')
const handleChange = (value: string) => {
setName(value)
onDataChange?.({ name: value }, value.length > 0)
}
return (
<div>
<h2>{payload.title}</h2>
<input value={name} onChange={(e) => handleChange(e.target.value)} />
</div>
)
}
Next.js のセットアップ
OnboardJS は React フックとブラウザー API を使用するため、Next.js App Router ではクライアントサイドレンダリングが必要です。
ステップコンポーネント - "use client" を追加する
すべてのステップコンポーネントはクライアントコンポーネントにする必要があります:
// components/WelcomeStep.tsx
'use client'
import { StepComponentProps } from '@onboardjs/react'
export const WelcomeStep: React.FC<StepComponentProps> = ({ payload }) => {
return <h1>{payload.title}</h1>
}
プロバイダーのラッパー - "use client" を追加する
プロバイダー用のクライアントラッパーを作成します:
// components/OnboardingWrapper.tsx
'use client'
import { OnboardingProvider } from '@onboardjs/react'
import { steps } from './steps'
export function OnboardingWrapper({ children }: { children: React.ReactNode }) {
return (
<OnboardingProvider
steps={steps}
onFlowComplete={(ctx) => console.log('Done!', ctx)}
>
{children}
</OnboardingProvider>
)
}
ページで使用する(App Router)
// app/onboarding/page.tsx
import { OnboardingWrapper } from '@/components/OnboardingWrapper'
import { OnboardingUI } from '@/components/OnboardingUI'
export default function OnboardingPage() {
return (
<OnboardingWrapper>
<OnboardingUI />
</OnboardingWrapper>
)
}
動的インポート(任意 - コード分割用)
動的インポートを使うと、初期バンドルサイズを削減できます:
// app/onboarding/page.tsx
import dynamic from 'next/dynamic'
const OnboardingWrapper = dynamic(
() => import('@/components/OnboardingWrapper').then(mod => mod.OnboardingWrapper),
{
ssr: false,
loading: () => <div>Loading onboarding...</div>
}
)
export default function OnboardingPage() {
return <OnboardingWrapper><OnboardingUI /></OnboardingWrapper>
}
ステップコンポーネントの動的読み込み(任意 - 大規模なフロー用)
ステップコンポーネントを遅延読み込みして、バンドルサイズを削減します:
// steps.tsx
'use client'
import dynamic from 'next/dynamic'
import { OnboardingStep } from '@onboardjs/react'
const WelcomeStep = dynamic(() => import('./components/WelcomeStep').then(m => m.WelcomeStep))
const ProfileStep = dynamic(() => import('./components/ProfileStep').then(m => m.ProfileStep))
const CompleteStep = dynamic(() => import('./components/CompleteStep').then(m => m.CompleteStep))
export const steps: OnboardingStep[] = [
{ id: 'welcome', component: WelcomeStep, nextStep: 'profile' },
{ id: 'profile', component: ProfileStep, nextStep: 'complete' },
{ id: 'complete', component: CompleteStep, nextStep: null }
]
Pages Router(レガシー)
Next.js Pages Router では "use client" は不要ですが、SSR を無効にしてください:
// pages/onboarding.tsx
import dynamic from 'next/dynamic'
const OnboardingFlow = dynamic(
() => import('@/components/OnboardingFlow'),
{ ssr: false }
)
export default function OnboardingPage() {
return <OnboardingFlow />
}
永続化
localStorage(シンプル)
<OnboardingProvider
steps={steps}
localStoragePersistence={{ key: 'onboarding_v1', ttl: 604800000 }}
>
カスタムバックエンド
<OnboardingProvider
steps={steps}
customOnDataLoad={async () => await fetchFromAPI()}
customOnDataPersist={async (ctx) => await saveToAPI(ctx)}
customOnClearPersistedData={async () => await clearAPI()}
>
条件付きナビゲーション
import { RoleSelectStep } from './components/RoleSelectStep'
import { AdminSetupStep } from './components/AdminSetupStep'
import { UserSetupStep } from './components/UserSetupStep'
{
id: 'role-select',
component: RoleSelectStep,
payload: {
options: [
{ value: 'admin', label: 'Admin' },
{ value: 'user', label: 'User' }
]
},
nextStep: (ctx) => ctx.flowData.role === 'admin' ? 'admin-setup' : 'user-setup'
}
条件付きステップ表示
{
id: 'admin-setup',
component: AdminSetupStep,
condition: (ctx) => ctx.flowData.role === 'admin'
}
詳細情報:リファレンスを参照
- references/step-config.md - ステップ設定オプションの全一覧
- references/hooks-api.md - useOnboarding API の全詳細
- references/patterns.md - 高度なパターン(バリデーション、イベント、プラグイン、Next.js)