A small, dependency-free checklist widget for any web app, with or
without a framework. It renders native buttons and announces progress
politely, and it only completes a step when your app says the work is
done.
$npm install @stepr/checklist
Live demo
Acme is a made-up project tool. Open a step from the checklist or use
the app's toolbar. Each step is completed by the app event that
finishes it, such as saving a form or finishing a tour, not by the
click that opens it.
Acme ProjectsSetup 0/0
Welcome to Acme
Nothing here yet. Open a step in the checklist to set up your
workspace.
Try the API
Events
Callbacks and return values appear here.
Examples
Copy any example as is. The JavaScript also works as TypeScript
because the package ships its own types. Tests run these exact
snippets against the built package and check that they match the
README.
Quick start without a bundler
The package is ESM only. With a bundler, just
import it. Without one, map the package name in an
import map and serve the page over HTTP. ES modules don’t load from
file://.
Activating a step only calls its onClick. Mark a step
done when the work actually happens, from any code that holds the
checklist. Steps without onClick are rendered as text.
import { createChecklist } from '@stepr/checklist';
const checklist = createChecklist({
container: '#onboarding',
title: 'Get started',
steps: [
{
id: 'profile',
label: 'Complete your profile',
onClick: () => openProfileForm(), // opening the form does not complete it
},
{ id: 'verify', label: 'Verify your email address' }, // text only
],
onChange: ({ progress }) => {
if (progress.completed === progress.total) showAllDoneMessage();
},
});
// Complete steps when the work is actually done, from anywhere in your app:
onProfileSaved(() => checklist.complete('profile'));
onEmailVerified(() => checklist.complete('verify'));
Persistence, reset and cleanup
Persistence is opt-in. Completed step ids are stored in
localStorage under your key. If storage is unavailable
or full, the checklist keeps working in memory.
import { createChecklist } from '@stepr/checklist';
const checklist = createChecklist({
container: '#onboarding',
title: 'Get started',
steps: [
{ id: 'profile', label: 'Complete your profile' },
{ id: 'invite', label: 'Invite a teammate' },
],
storageKey: 'my-app:onboarding', // restored on creation, saved on change
});
checklist.complete('invite'); // true, and saved
checklist.complete('invite'); // false: already complete, nothing saved
checklist.getProgress(); // { completed: 1, total: 2 }
checklist.reset(); // marks every step incomplete, and saves that
checklist.destroy(); // removes the widget; saved progress is kept
localStorage.removeItem('my-app:onboarding'); // forget saved progress
Start a Stepr tour from a step
The checklist doesn’t know about tours. Your app connects the two
libraries with callbacks: the step’s onClick starts the
tour, and the tour’s onComplete completes the step.
Closing the tour early leaves the step open.
Stepr is a
separate package that you install yourself.
import { createChecklist } from '@stepr/checklist';
import { createTour } from 'stepr';
const tour = createTour({
steps: [
{ target: '#new-project', title: 'Projects', description: 'Start here.' },
{ target: '#invite', title: 'Invite your team' },
],
onComplete: () => checklist.complete('tour'), // finished: tick it off
onExit: () => {}, // closed early: the step stays incomplete
});
const checklist = createChecklist({
container: '#onboarding',
title: 'Get started',
steps: [
{
id: 'tour',
label: 'Take the product tour',
onClick: () => {
if (!tour.start()) console.warn('No tour target is visible');
},
},
],
});
Theme with CSS custom properties
Set the properties on the widget or on any ancestor, such as the
container. This is the demo’s “Violet” theme. If you change colors,
check the contrast yourself.