TourKit
@tour-kit/checklistsProviders

ChecklistProvider

ChecklistProvider: configure task definitions, dependencies, storage, and analytics integration for your checklist instance

ChecklistProvider

The root provider that manages checklist state and makes it available throughout your application.

Usage

import { ChecklistProvider } from '@tour-kit/checklists';

const checklists = [
  {
    id: 'onboarding',
    title: 'Get Started',
    tasks: [
      { id: 'step1', title: 'First step' },
      { id: 'step2', title: 'Second step' },
    ],
  },
];

function App() {
  return (
    <ChecklistProvider checklists={checklists}>
      <YourApp />
    </ChecklistProvider>
  );
}

Props

Prop

Type

Persistence

Enable persistence to save checklist state across sessions:

<ChecklistProvider
  checklists={checklists}
  persistence={{
    enabled: true,
    storage: 'localStorage', // 'localStorage' | 'sessionStorage'
    key: 'tour-kit:checklists', // Storage key
  }}
>
  <YourApp />
</ChecklistProvider>

Storage Format

The provider persists:

  • Completed tasks per checklist
  • Dismissed checklists
  • Timestamp of last update
{
  completed: {
    'onboarding': ['step1', 'step2'],
    'setup': ['verify-email']
  },
  dismissed: ['old-checklist'],
  timestamp: 1234567890
}

Persistence is automatically loaded on mount and saved on every state change.

Context

Pass custom context to make it available in task conditions:

const user = {
  id: '123',
  name: 'John Doe',
  role: 'admin',
  plan: 'premium',
};

const data = {
  projectCount: 5,
  teamSize: 10,
};

<ChecklistProvider
  checklists={checklists}
  context={{ user, data }}
>
  <YourApp />
</ChecklistProvider>

Tasks can then use this context:

const tasks = [
  {
    id: 'admin-task',
    title: 'Admin only',
    when: (context) => context.user.role === 'admin',
  },
  {
    id: 'premium-task',
    title: 'Unlock premium',
    when: (context) => context.user.plan === 'free',
  },
  {
    id: 'milestone',
    title: 'Create 10 projects',
    completedWhen: {
      custom: (context) => context.data.projectCount >= 10,
    },
  },
];

Event Handlers

Track user interactions with event callbacks:

<ChecklistProvider
  checklists={checklists}
  onTaskComplete={(checklistId, taskId) => {
    console.log(`Task ${taskId} completed in ${checklistId}`);
    analytics.track('checklist_task_completed', {
      checklist: checklistId,
      task: taskId,
    });
  }}
  onTaskUncomplete={(checklistId, taskId) => {
    console.log(`Task ${taskId} uncompleted`);
  }}
  onChecklistComplete={(checklistId) => {
    console.log(`Checklist ${checklistId} completed!`);
    analytics.track('checklist_completed', { checklist: checklistId });
  }}
  onChecklistDismiss={(checklistId) => {
    console.log(`Checklist ${checklistId} dismissed`);
  }}
  onTaskAction={(checklistId, taskId, action) => {
    console.log(`Task action:`, action);

    // Custom handling for specific actions
    if (action.type === 'tour') {
      // Launch tour via your tour system
      tourSystem.start(action.tourId);
    }
    if (action.type === 'modal') {
      // Open modal via your modal system
      modalSystem.open(action.modalId);
    }
  }}
>
  <YourApp />
</ChecklistProvider>

Task Actions

The provider automatically handles these action types:

{
  type: 'navigate',
  url: '/dashboard',
  external: false // Opens in same window
}

{
  type: 'navigate',
  url: 'https://example.com',
  external: true // Opens in new tab
}

Callback

{
  type: 'callback',
  handler: async () => {
    await api.doSomething();
    console.log('Custom logic executed');
  }
}

Tour (requires integration)

{
  type: 'tour',
  tourId: 'intro-tour'
}

Tour actions require integration with a tour system. Use onTaskAction to handle tour launching.

{
  type: 'modal',
  modalId: 'invite-modal'
}

Custom

{
  type: 'custom',
  data: { anything: 'you want' }
}

Handle custom actions via onTaskAction:

onTaskAction={(checklistId, taskId, action) => {
  if (action.type === 'custom') {
    // Handle your custom action
    console.log(action.data);
  }
}}

Automatic Task Completion

By default, tasks auto-complete when their action is executed. Disable this:

const tasks = [
  {
    id: 'manual-task',
    title: 'Do something',
    action: { type: 'navigate', url: '/page' },
    manualComplete: false, // Don't auto-complete
  },
];

Then complete manually:

const { completeTask } = useChecklist('my-checklist');

// Later...
completeTask('manual-task');

Checklist Lifecycle

const checklist = {
  id: 'onboarding',
  title: 'Get Started',
  tasks: [...],

  onComplete: () => {
    console.log('All tasks completed!');
    // Show celebration modal
    // Award achievement
    // Navigate to next step
  },

  onDismiss: () => {
    console.log('Checklist dismissed');
    // Track dismissal
    // Maybe show alternative guidance
  },

  dismissible: true, // Allow dismissing
  hideOnComplete: true, // Auto-hide when done
};

Multiple Checklists

Provide multiple checklists for different user journeys:

const checklists = [
  {
    id: 'onboarding',
    title: 'Getting Started',
    tasks: [
      { id: 'create-account', title: 'Create account' },
      { id: 'verify-email', title: 'Verify email' },
    ],
  },
  {
    id: 'advanced-setup',
    title: 'Advanced Setup',
    tasks: [
      { id: 'api-keys', title: 'Generate API keys' },
      { id: 'webhooks', title: 'Configure webhooks' },
    ],
  },
  {
    id: 'feature-discovery',
    title: 'Explore Features',
    tasks: [
      { id: 'try-feature-a', title: 'Try Feature A' },
      { id: 'try-feature-b', title: 'Try Feature B' },
    ],
  },
];

<ChecklistProvider checklists={checklists}>
  <YourApp />
</ChecklistProvider>

Best Practices

Start Simple

Begin with a simple checklist and add complexity as needed:

// Good: Start simple
const checklist = {
  id: 'onboarding',
  title: 'Get Started',
  tasks: [
    { id: 'step1', title: 'First step' },
    { id: 'step2', title: 'Second step' },
  ],
};

// Add features incrementally
const enhancedChecklist = {
  ...checklist,
  tasks: checklist.tasks.map((task, i) => ({
    ...task,
    dependsOn: i > 0 ? [checklist.tasks[i - 1].id] : undefined,
    action: { type: 'navigate', url: `/step-${i + 1}` },
  })),
};

Validate Circular Dependencies

Always validate dependencies during development:

import { hasCircularDependency } from '@tour-kit/checklists';

const checklist = {
  id: 'test',
  tasks: [
    { id: 'a', dependsOn: ['b'] },
    { id: 'b', dependsOn: ['a'] }, // Circular!
  ],
};

if (hasCircularDependency(checklist.tasks)) {
  console.error('Circular dependency detected!');
}

Context Best Practices

Keep context flat and predictable:

// Good: Flat, predictable structure
const context = {
  user: {
    id: '123',
    role: 'admin',
    plan: 'premium',
  },
  data: {
    projectCount: 5,
    hasTeam: true,
  },
};

// Avoid: Deep nesting, computed values
const context = {
  user: {
    profile: {
      settings: {
        preferences: { /* ... */ }
      }
    }
  },
  // Computed values can cause re-renders
  computed: {
    get isEligible() {
      return checkComplexLogic();
    }
  }
};

Event Tracking

Use event handlers for analytics:

<ChecklistProvider
  checklists={checklists}
  onTaskComplete={(checklistId, taskId) => {
    analytics.track('task_completed', {
      checklist_id: checklistId,
      task_id: taskId,
      timestamp: Date.now(),
    });
  }}
  onChecklistComplete={(checklistId) => {
    analytics.track('checklist_completed', {
      checklist_id: checklistId,
      timestamp: Date.now(),
    });

    // Award achievement
    achievements.unlock(`${checklistId}_complete`);
  }}
>
  <YourApp />
</ChecklistProvider>

On this page