Skip to content

FRD-037: Onboarding Progress Bar

FieldValue
OwnerDavid Holmes
StatusDraft
Last Updated2026-05-26
Target Releasev2.0.0
TypeWidget
SizeS
PriorityP1 — SaaS Widget

Document Summary

Build an Onboarding Progress Bar widget providing a checklist with progress percentage, step completion toggling, ManagedChecklist integration, and a persistent state callback. It enhances the existing managed-checklist.tsx with a progress header, percentage display, and onboarding-specific UX patterns.


Introduction

Overview

SaaS applications commonly display an onboarding checklist that guides new users through setup steps (create a project, invite a teammate, connect an integration). The design system provides ManagedChecklist for general-purpose checklists, but it lacks a progress header, percentage bar, completion celebration, and the persistent-state pattern needed for onboarding flows. Teams build these patterns from scratch.

Goals

  • Provide an OnboardingProgressBar widget with a visual progress bar and percentage display.
  • Integrate with ManagedChecklist for the step list with completion toggling.
  • Support a persistent state callback so completion state survives page refreshes.
  • Provide completion celebration (confetti or checkmark animation) when all steps are done.
  • Support collapsible mode so the checklist can be minimized after initial setup.
  • Ship with Storybook stories and unit tests.

Non-Goals

  • Multi-page wizard navigation (PanelWizard covers that).
  • Gamification (points, levels, streaks).
  • User analytics or onboarding funnel tracking.

Scope

In Scope

ItemDescription
Progress headerA bar showing completion percentage with “X of Y completed” text.
Step checklistManagedChecklist-based step list with toggleable completion per step.
Persistent stateonStateChange callback fires on every completion toggle; consumer persists to localStorage or API.
Completion celebrationVisual indicator (animated checkmark, confetti) when all steps are completed.
Collapsible modeThe checklist can collapse to show only the progress bar header.
DismissibleAn optional “Dismiss” action that hides the widget entirely (calls onDismiss callback).
Stories and testsStorybook stories for all states; unit tests for progress calculation and state management.

Out of Scope

ItemReason
Multi-page wizardPanelWizard handles that pattern.
Step-specific content/formsSteps are labels with optional descriptions; forms are in the application.
Analytics trackingConsumer responsibility via callbacks.

Users and Pain Points

UserPain Point
SaaS developersBuild onboarding checklists from scratch for every product; inconsistent patterns.
Product managersCannot easily A/B test onboarding flows without a standard widget.
New usersNo visual indication of setup progress; unclear what steps remain.
Growth teamsOnboarding completion rates are hard to improve without a consistent, polished experience.

Definitions

TermDefinition
Onboarding stepA single setup task the user needs to complete (e.g., “Create your first project”).
Completion percentage(completedSteps / totalSteps) * 100.
Persistent stateStep completion state that survives page navigation and browser refresh.
DismissibleThe widget can be permanently hidden by the user.

Current State

  • ManagedChecklist (src/components/widgets/managed-checklist.tsx): General-purpose checklist with ManagedListItem entries supporting checked state, edit mode, and term-definition variants. No progress bar, percentage, or onboarding-specific features.
  • ChecklistFoundation: Low-level primitives (ChecklistRow, ChecklistContainer, etc.) used by ManagedChecklist.
  • No onboarding-specific widget exists.

Proposed Solution

Build src/components/widgets/onboarding-progress-bar.tsx:

Structure

OnboardingProgressBar
├── Progress header
│ ├── Title ("Get started with [Product]")
│ ├── Progress bar (filled proportionally)
│ ├── Percentage text ("3 of 5 completed")
│ └── Collapse/Dismiss actions
├── Step list (collapsible)
│ ├── Step 1: [check] "Create your first project" — description
│ ├── Step 2: [check] "Invite a team member" — description
│ └── ...
└── Completion celebration (when all done)

Progress Bar

A horizontal bar using the existing progress bar styles (or a simple div with bg-primary and width percentage). Animated fill using motion tokens.

Step List

Each step renders as a ManagedChecklist item (or a simplified version). Clicking a step toggles its completion. Optionally, clicking a step can navigate to the relevant page via an onStepClick callback.

Persistent State

The widget accepts completedStepIds: string[] (controlled) and fires onStateChange(completedStepIds) on every toggle. The consumer persists this array to localStorage, a cookie, or an API.

Completion

When all steps are completed, the progress bar fills to 100% and an animated checkmark or brief confetti animation plays. An optional “All done!” message replaces the step list.


Requirements

Requirement Priorities

  • Must Have: Progress bar with percentage, step list with toggleable completion, state change callback.
  • Should Have: Collapsible mode, dismissible, step click navigation callback.
  • Could Have: Completion celebration animation, “All done” message, step reordering.

Functional Requirements

IDRequirementPriority
FR-01Widget displays a progress bar with fill proportional to completed steps.Must
FR-02”X of Y completed” text displays above or beside the progress bar.Must
FR-03Step list renders each step with a checkbox, title, and optional description.Must
FR-04Clicking a step checkbox toggles its completion state.Must
FR-05onStateChange callback fires with updated completedStepIds array on every toggle.Must
FR-06Widget accepts completedStepIds as controlled state.Must
FR-07Collapsible mode hides the step list, showing only the progress bar header.Should
FR-08”Dismiss” action hides the entire widget and calls onDismiss.Should
FR-09onStepClick callback fires when a step title is clicked (for navigation).Should
FR-10Completion animation plays when all steps are completed.Could
FR-11Progress bar fill animates smoothly using motion tokens.Should

Non-Functional Requirements

IDRequirementTarget
NFR-01Widget renders with 10 steps in < 10ms.React Profiler measurement.
NFR-02Bundle size< 4 KB gzipped (excluding ManagedChecklist deps).
NFR-03Progress bar animationUses --motion-standard (160ms) for fill transitions.
NFR-04Reduced-motionProgress bar fill transition is instant under prefers-reduced-motion: reduce.
NFR-05Dark modeFull token-based dark mode support.

API/Interface Requirements

interface OnboardingStep {
id: string;
title: string;
description?: string;
icon?: ReactNode;
}
interface OnboardingProgressBarProps {
title?: string; // default "Get started"
steps: OnboardingStep[];
completedStepIds: string[];
onStateChange: (completedStepIds: string[]) => void;
onStepClick?: (stepId: string) => void;
onDismiss?: () => void;
collapsible?: boolean; // default true
defaultCollapsed?: boolean; // default false
completionMessage?: string; // default "All done!"
className?: string;
}

Accessibility Requirements

IDRequirement
A11Y-01Progress bar uses role="progressbar" with aria-valuenow, aria-valuemin=0, aria-valuemax=100.
A11Y-02Step checkboxes are standard role="checkbox" with aria-checked.
A11Y-03Collapse toggle has aria-expanded and aria-controls pointing to the step list.
A11Y-04Completion state is announced via aria-live="polite" region.
A11Y-05Completion animation respects prefers-reduced-motion: reduce.
A11Y-06All components pass axe-core automated checks with zero violations.

Content and Documentation Requirements

IDRequirement
DOC-01Storybook docs page with usage guidelines, prop table, and interactive examples.
DOC-02Recipe showing OnboardingProgressBar with localStorage persistence.
DOC-03Recipe showing OnboardingProgressBar with API-backed persistence (TanStack Query).
DOC-04Guidelines on defining good onboarding steps (concise titles, actionable descriptions).

Dependencies

DependencyTypeRisk
src/components/widgets/managed-checklist.tsxInternalLow — step list foundation.
src/components/ui/button.tsxInternalLow — dismiss/collapse actions.
src/styles/motion.cssInternalLow — progress bar animation tokens.

Risks and Tradeoffs

RiskLikelihoodImpactMitigation
ManagedChecklist API doesn’t perfectly fit onboarding use caseMediumLowUse ManagedChecklist internals selectively or build a simplified step list.
Completion animation is distractingLowLowRespect reduced-motion; keep animation brief (< 500ms).
Persistent state conflicts when multiple tabs are openLowMediumDocument that consumers should use a single source of truth (API) for multi-tab scenarios.

Open Questions

#QuestionOwnerStatus
OQ-01Should the widget support step dependencies (step 2 locked until step 1 is complete)?David HolmesOpen
OQ-02Should dismissed state be managed internally or entirely by the consumer?David HolmesOpen
OQ-03Should the completion celebration be confetti, animated checkmark, or configurable?David HolmesOpen

Acceptance Criteria

#Criterion
AC-01Widget renders a progress bar with fill proportional to completed steps and “X of Y” text.
AC-02Step checkboxes toggle completion state and fire onStateChange.
AC-03Collapsible mode hides the step list, showing only the progress header.
AC-04Dismiss action hides the widget and calls onDismiss.
AC-05Progress bar animation uses motion tokens and respects reduced-motion.
AC-06All components pass axe-core checks with zero violations.
AC-07Storybook stories exist for: empty, partial progress, complete, collapsed, dismissed.
AC-08pnpm typecheck and pnpm vitest run --project unit pass with zero errors.

LLM Handoff Instructions

When implementing this FRD:

  1. Create src/components/widgets/onboarding-progress-bar.tsx.
  2. Progress header: A card-like container with title, progress bar (div with bg-primary width set to completion percentage), and “X of Y completed” text.
  3. Step list: Render steps as checkbox rows. Consider reusing ChecklistRow from checklist-foundation or building a simpler variant. Each row: checkbox + title + optional description.
  4. State management: The widget is fully controlled. completedStepIds is the source of truth. On checkbox toggle, compute the new array and call onStateChange.
  5. Collapsible: Use a simple useState for collapsed state with aria-expanded on the toggle button. Animate height via motion tokens.
  6. Dismiss: An X button or “Dismiss” link calls onDismiss. The widget renders null after dismissal (consumer controls visibility).
  7. Completion: When completedStepIds.length === steps.length, show a success state. Consider a brief animated checkmark using CSS keyframes.
  8. Stories in src/components/widgets/onboarding-progress-bar.stories.tsx. Include: Empty (0%), Partial (40%), MostlyDone (80%), Complete (100%), Collapsed, WithStepClick.
  9. Tests in src/components/widgets/onboarding-progress-bar.test.tsx. Test toggle, progress calculation, collapse, dismiss.

Key files:

  • src/components/widgets/managed-checklist.tsx — checklist patterns.
  • src/components/widgets/checklist-foundation.tsx — low-level primitives.
  • src/styles/motion.css — animation tokens.

Decision Log

DateDecisionRationale
2026-05-26Fully controlled component (consumer manages completedStepIds).Persistence strategy varies (localStorage, API, cookie); widget should not choose.
2026-05-26Simplified step list rather than full ManagedChecklist integration.Onboarding steps don’t need edit mode, term-definition variants, or drag-to-reorder.
2026-05-26Completion celebration is optional and respects reduced-motion.Accessibility and user preference take priority over delight.

Document History

VersionDateAuthorChanges
0.12026-05-26David HolmesInitial draft.