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:
Navigate
{
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.
Modal (requires integration)
{
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>Related
- useChecklist - Access checklist state
- useChecklistPersistence - Manage persistence
- Checklist Types - Type definitions