A step list represents a user's progression through an application or multi-page form. It serves as a table of contents and a way to quickly see where they are and what they should be working on next.
Start, Resume, and Edit links
A user interacts with the steps through "Start", "Resume", and "Edit" links.
In the React component, the links' href
properties are determined by the
step
object's href
property. One can also optionally pass an
onStepLinkClick
function that will cancel the default link behavior and call
onStepLinkClick
with href
as a parameter for apps that handle routing with
JavaScript.
When a step has substeps and is incomplete, the href
property should be set to
match the href
of the current substep—that is, the first incomplete substep.
The "Edit" button will only appear on substeps that have been completed.
<StepList>
The StepList
component is the preferred method for building a step list, since it handles all the state logic necessary to produce its markup. A step is represented by an object with text, progress, and routing information and can optionally include an array of substeps as well as a description.
Code snippet
Props
Name | Type | Default | Description |
---|---|---|---|
steps required | StepObject[] | An array of step objects that contain text, state, link/button URLs and other info needed to render steps. | |
component | StepLinkProps['component'] | When provided, this will render the passed in component for all link elements. This is useful when
integrating with React Router's | |
showSubSubSteps | boolean | false | Whether or not to render a substep's substeps. |
onStepLinkClick | StepLinkProps['onClick'] | Function called when a step's Edit, Start, or Resume button/link is
clicked. The step's | |
completedText | string | 'Completed' | |
editText | string | 'Edit' | |
resumeText | string | 'Resume' | |
startText | string | 'Start' | |
actionsLabelText | string | 'Primary actions for %{step}' | A template string for the aria-label describing a step's actions where
the substring |
descriptionLabelText | string | 'Description for %{step}' | A template string for the aria-label for a step's description where
the substring |
substepsLabelText | string | 'Secondary actions for %{step}' | A template string for the aria-label describing a step's substeps where
the substring |
<Step>
Step Object
Name | Type | Description |
---|---|---|
completed | bool | Whether the step has been completed |
component | element, func | When provided, this will render the passed in component for link elements in this Step. This is useful when integrating with React Router's <Link> or using your own custom component. |
description | string | Additional text to dsiplay under (only rendered for top-level steps) |
heading Required | string | Text to display as the step heading |
headingLevel | '1', '2', '3', '4', '5' | Heading type to override default <h2> . |
href Required | string | URL or partial URL that routes to the step. Will be passed to onStepLinkClick as first parameter |
id | string | Unique string representing the step. WIll be passed to onStepLinkClick as second parameter |
isNextStep | bool | Whether this is the next unstarted step |
linkText | string | Alternative text for the link or button for this step. Will override the defaults |
onClick | func | onClick handler for this specific step's link/button |
started | bool | Whether the step has been started |
steps | StepObject[] | Array of substeps |
Guidance
Managing list state
Substeps
The <StepList>
component takes an array of step objects. From there steps can
be broken down infinitely into sub-steps. This allows us to have unique URLs for
each part of a step; however, by default we only display two levels of this tree
—the step and substep. This default behavior should remain unchanged except
for special circumstances. It is better not to overwhelm the user with showing
all the substeps and giving them names.
We do, nonetheless, encourage the use of sub-substeps that are not visible where
these substeps span multiple pages and have their own unique URLs. If, for
example, the user completes the first page of the household > overall
substep
where they list the household members but has not completed the second page
where they define those members' relationships to each other, we want the
"Resume" button to take them back to the relationships page and not the first
page where they entered their names. This, of course, requires an extra
steps-building process to update a top-level steps' href
property by
traversing the substep tree to find the first incomplete step. See the
Completed, started, and isNextStep section
below for an example JavaScript function that can change the href
of steps
based on their substeps.
Completed, started, and isNextStep
The state of a step object will be defined for these purposes as the values
of its completed
, started
, and isNextStep
properties. These correspond to
different visual states when rendered by the <StepList>
, showing "Completed",
"Resume", or "Start" respectively. For steps with substeps, the state should be
representative of the collective states of its substeps. For example, if a step
has substeps that have completed: false
, that step should not have
completed: true
because not all of its substeps have been completed. Similarly
a step can only be started
if at least one of its substeps has been started
.
This should be true for each of the substep's substeps and so on. Below is an
example function that can propagate this state information up from the smallest
substep to the largest step before passing the steps array to the <StepList>
component.
function propagateSubstepState(step) {
if (step.steps) {
const steps = step.steps.map(propagateSubstepState);
const newStep = {
...step,
steps,
started: steps.some((s) => s.started),
completed: steps.every((s) => s.completed),
};
if (!newStep.completed) {
const nextStep = steps.find((s) => !s.completed);
newStep.href = nextStep.href;
}
return newStep;
} else {
return step;
}
}
// ...
//
// Render function:
const steps = rawSteps.map(propagateSubstepState);
return <StepList steps={steps} />;
Customization
The following Sass variables can be overridden to customize StepList patterns: