mcpField
O
onboardjs-react

onboardjs-react

github.com/onboardjs開発385 回インストール39 週間前に更新
リポジトリ

onboardjs-react について

onboardjs-react は、OnboardJS でオンボーディングフローを構築するための React 統合ガイドです。独自 UI を作り、フロー状態やナビゲーションをライブラリに任せたい開発者向けです。

主な機能

  1. 01React プロジェクトとパッケージマネージャーの検出
  2. 02ステップコンポーネントと Provider の設定
  3. 03描画とナビゲーション用のフック
  4. 04ステップ ID による進捗管理
  5. 05Next.js のクライアント設定と遅延読み込み
  6. 06ローカルおよび独自バックエンドへの永続化

活用シーン

  1. 01React アプリへのオンボーディング追加
  2. 02オンボーディング設定の Next.js 対応
  3. 03ステップ進捗の追跡
  4. 04ローカル保存または API による状態保存

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/onboardjs/onboardjs-skills --skill onboardjs-react

インストール後、Claude Code で/onboardjs-reactを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

references/
hooks-api.md
patterns.md
step-config.md

詳細

OnboardJS React 統合

OnboardJS は、ユーザーのオンボーディング体験を構築するためのヘッドレスライブラリです。UI はご自身で制御し、OnboardJS がフローのロジック、状態、永続化、ナビゲーションを処理します。

開始する前に

1. React プロジェクトを確認する - React の依存関係が含まれる package.json があるか確認します。React プロジェクトでない場合は、ユーザーにその旨を伝えてください。

2. パッケージマネージャーを検出する - ロックファイルを確認し、適切なインストールコマンドを判断します:

ロックファイルパッケージマネージャーインストールコマンド
pnpm-lock.yamlpnpmpnpm add @onboardjs/core @onboardjs/react
yarn.lockyarnyarn add @onboardjs/core @onboardjs/react
bun.lockbbunbun add @onboardjs/core @onboardjs/react
package-lock.json またはなしnpmnpm 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'
}

詳細情報:リファレンスを参照

コメント