Progress Path
Show progress through ordered sections of items, with mastery and section milestones, such as a course.
import { ProgressPath, ProgressPathLesson, ProgressPathSection } from '@youj/react'
Installation & usage
npm i @youj/reactFor an app already set up with npx @youj/cli init, which installs the peers (@youj/core, @youj/motion, motion and Base UI) and wires the provider. New app? Start at Installation.
Use a progress path for anything learned in order: a language course, an onboarding program, a training plan. Lessons are nodes on a trail that swings across the column, grouped into sections that each take a chart color and close on a trophy milestone. Each node wears a segmented ring, one segment per level of mastery. Lessons before the current one are done, the current one is an ink disc glowing in its section's color with a Start callout beside it, and the rest are locked. The trail is solid behind you and dotted ahead. For steps of a form, use a Stepper; for a pipeline's stages, a Stage Rail.
import { ProgressPath, type ProgressPathSection } from '@youj/react'
const sections: ProgressPathSection[] = [
{
id: 'basics',
eyebrow: 'Section 1',
title: 'Basics',
lessons: [
{ id: 'greetings', title: 'Greetings', detail: '6 min', mastery: 4 },
{ id: 'numbers', title: 'Numbers', detail: '7 min', mastery: 1 },
{ id: 'basics-check', title: 'Basics checkpoint', milestone: true },
],
},
]
<ProgressPath sections={sections} current="numbers" onSelect={(lesson) => open(lesson.id)} />current is the lesson up next: those before it are done and those after it locked; null means the course is finished. Leave it out and the first lesson not fully mastered is up next. mastery counts the levels a lesson has mastered, out of levels (4 by default), and a done lesson at full mastery wears a crown. detail adds a mono line beside a lesson's title, and milestone draws a lesson as a trophy that closes its section. Sections take the chart colors in turn, or their own tone.
The trail swings wider as the column grows, and lesson titles sit beside their nodes once it's at least 32rem wide; narrower, the nodes carry the path alone. onSelect opens a lesson that's done or current. A locked one shakes its head and plays the error cue.
Description
Two sections of lessons with a checkpoint each, where Finish lesson moves the current lesson on.
Code
progress-path-demo.tsx, the Demo story. The component itself comes from the package.
Reference
Propssections, current, levels… (7)
Props
| Prop | Type | |
|---|---|---|
sectionsRequired | ProgressPathSection[] | – |
current | string | nullThe lesson up next: those before it are done and those after it locked. | – |
levels | numberLevels of mastery per lesson, one ring segment each. default 4 | 4 |
onSelect | (lesson: ProgressPathLesson, section: ProgressPathSection) => voidCalled when a lesson that isn't locked is opened. | – |
label | stringAccessible name. Default: the labels' "Progress path". | – |
locale | stringDefault: the YoujProvider locale. | – |
sound | booleanPlays the success cue when the current lesson moves on. default true | true |
Other props pass through: extends ComponentProps<'div'>. | ||
StylingParts and data attributes
Styling
Parts: progress-path, progress-path-trail, progress-path-walked (with data-walked), progress-path-section, progress-path-head, progress-path-eyebrow, progress-path-title, progress-path-value, progress-path-node (with data-state and data-milestone), progress-path-glow, progress-path-ring, progress-path-level (with data-state), progress-path-disc, progress-path-label (with data-side) and progress-path-callout.
MotionFirst view, current moves on, current lesson… · reduced motion
Motion
| Moment | Tokens | ||
|---|---|---|---|
| First viewthe walked trail draws itself, segment by segment | duration.slowease.emphasized340ms · cubic-bezier(0.6, 0, 0.1, 1) | 340mscubic-bezier(0.6, 0, 0.1, 1) | |
| Current moves onthe next segment draws and the Start callout glides after it | duration.slowease.emphasized340ms · cubic-bezier(0.6, 0, 0.1, 1) | 340mscubic-bezier(0.6, 0, 0.1, 1) | |
| Current lessona slow ping from its glow while the path is on screen | duration.deliberateease.exit560ms · cubic-bezier(0.4, 0, 1, 1) | 560mscubic-bezier(0.4, 0, 1, 1) | |
| Locked lesson pressedthe node shakes its head | duration.baseease.standard220ms · cubic-bezier(0.2, 0, 0, 1) | 220mscubic-bezier(0.2, 0, 0, 1) |
Reduced motion
The trail is drawn in place, the callout jumps, and there's no ping or shake.
Reduced motion
The trail is drawn in place, the callout jumps to the next lesson, and the current lesson glows without pinging.
AccessibilityKeyboard, ARIA
Accessibility
- The path is a group named by
label(default: the labels' "Progress path") and described by how to move through it; each section is named by its title. - Each lesson is a button named by its title, its place in the course, its status and its mastery ("Numbers, lesson 2 of 3, up next, mastery 1 of 4"). The current one has
aria-current="step", and locked ones arearia-disabled. - The lessons are one tab stop, starting on the current lesson. Up and down walk the path, left and right do too (mirrored in RTL), and Home and End jump to its ends.
- A section's progress is spoken with its count ("1 of 3 lessons").
- Its words come from the labels (
progressPath,progressPathHint,lessonItem,milestoneItem,lessonDone,lessonCurrent,lessonLocked,lessonStart,sectionProgress), translated by the language packs.