Progress Stepper
A ProgressStepper is designed to orient a user within an interactive experience by breaking down extended tasks into 'steps'. This makes multi-part flows easier to estimate and complete by grouping related inputs, content or interactions into manageable chunks. Utilising a ProgressStepper acknowledges the value of a user's time and effort, and provides context and purpose to aid in successfully completing an interaction.
Experimental but encouraged!
Our progress-stepper component has been flagged as "experimental" as it is very new. Its use is encouraged, as is any feedback you can provide about the way the component works, the API design or any other concerns.
Installation
npm install @nib/progress-stepper
Note: You will also need to install the peerDependencies @nib/icons and @nib-components/theme.
Usage
The progress stepper is easy to drop-in and use. The package includes a custom useProgressStepper
hook to use in conjunction with the ProgressStepper
component to manage the stepper using local component state. See below example to demonstrate the simple usage of Progress Stepper.
import {ProgressStepper, useProgressStepper} from '@nib/progress-stepper';() => {const testSteps = [{title: 'First Step',isAccessed: false,isDisabled: false,isComplete: false},{title: 'Second Step',isAccessed: false,isDisabled: false,isComplete: false}];// Pass initial steps and currentStep to the hookconst {currentStep, steps, goToStep} = useProgressStepper(testSteps, 0);return <ProgressStepper steps={steps} currentStep={currentStep} goToStep={goToStep} collapseBelow="xl" />;};
Within a more complex multi-page flow, or an app with conditional logic, you may want to store the stepper state in a global context rather than use this local custom hook. Then you can make use of framework-specific features and routing.
Interactive demo
Props
ProgressStepper
Prop | Type | Default | Description |
---|---|---|---|
steps (required) | Step Type | This is the heart of the ProgressStepper. It contains individual states and attributes for each Step according to an expected shape. | |
align | string | inline | Selects between horizontally or vertically aligned variations of ProgressStepper. Accepted values are stacked or inline . |
fill | boolean | true | Sets the ProgressStepper to fill its parent container. When false , each contained Step will hug to the width of its respective title . |
showIcons | boolean | true | Top level prop to show or hide icons. If icons are not defined for all configured steps , this prop will have no effect. |
isGated | boolean | true | Toggles the behaviour where future steps are disabled by default. See [isGated](#isGated & isDisabled) |
collapseBelow | string | Breakpoint at which ProgressStepper collapses down to its interactive mobile variant. If not specified, ProgressStepper will not collapse. | |
stepWidth | string | Nominates a consistent width to be applied to all steps. Only applies if the fill prop is set to false . | |
currentStep (required) | number | Indicates the current/active step index. | |
goToStep | function | Accepts the step index as input. This function will set the indicated step as active. |
Step Type
Prop | Type | Default | Description |
---|---|---|---|
title (required) | string | Title of the step. | |
icon | component | An icon to be displayed along with the title of the step. Must be a valid graphic icon defined in @nib/icons. If one step has an icon, all steps must have icons. | |
href | string | Nominates the target url for when the step is clicked. | |
isAccessed (required) | boolean | Marks the step as having been accessed by the user. | |
isDisabled (required) | boolean | Marks the step as presently inaccessible to the user, pending other actions or conditions. | |
isComplete (required) | boolean | Marks the step as having been completed by the user. Has similar function to isAccessed but has a specific impact on the progress bar between nodes. | |
component | component | a | The component of the step. For example a NextLink component. |
useProgressStepper
This is a custom hook which is exported as part of the @nib/progress-stepper
package.
Input arguments
Arguments | Type | Default | Description |
---|---|---|---|
steps (required) | Step Type | This is the heart of the ProgressStepper. It contains individual states and attributes for each Step according to an expected shape. | |
currentStep (required) | number | Indicates the initial active step index. |
Returned arguments
Variables | Type | Default | Description |
---|---|---|---|
currentStep | number | Indicates the active step index. | |
steps | Step Type | Returns the steps and their respective states | |
goToNextStep | function | This function will help to proceed to next step. State changes are handled by hook. | |
goToPreviousStep | function | This function will help to proceed to previous step. State changes are handled by hook. | |
goToStep | function | Takes the step index as input. This function will make the indicated step as active | |
setSteps | function | If steps states are handled manually,this funcation helps to update the state |
Props and state management
isGated & isDisabled
ProgressStepper
is designed to guide and orient the user within a linear flow. While a user may choose to navigate backwards to correct or review previously completed Steps, an overall task should be assumed to be generally linear in nature.
To reflect this, the isGated
prop sets incomplete steps to disabled by default. Disabled steps remain visible, as they are important to the user's ability to estimate the effort required to complete, anticipate next steps, and orient to the overall task, but are otherwise unable to be interacted with directly. A disabled step typically implies that certain criteria need to be met to enable it, such as completion of a prior step.
The isDisabled
prop can be applied separately and individually to the isGated
prop. This may be desired in certain contexts, such as when a user clicks 'Submit' - locking in their responses and providing a Summary screen as the final Step in a flow.
isActive
When a user first enters a flow, the first Step should be set as active, with subsequent steps gated by default.In certain contexts, a user may be 'parachuted' into a later Step, with prior steps considered to be autofilled or non-essential. In these circumstances, however, any inputs or information related to those Steps should be able to be reviewed and corrected by the user.
isComplete
As a user completes a step, it should be marked as isComplete
, with the next step in sequence being marked isActive
. Inversely, when a step is marked active or accessed, prior steps should be marked as isComplete
- which necessitates realtime validation occurring on each page before a user navigates away. isAccessed
and isComplete
have similar function, but have different implications for the progress bar between nodes.
isAccessed
Any steps that have been accessed by the user should be marked as isAccessed. This ensures that if a user navigates to a prior step (or later in the case of an ungated Stepper), the ProgressStepper
reflects that they are able to return to the latest isAccessed
step.
Considerations
Stacked Progress Stepper
In contexts or flows where a continually visible sidebar navigation is desired, the stacked (vertical) variation - depicted below, - may be utilised in a column layout alongside its related content. Both stacked
and inline
variations observe the collapseBelow
prop in the same way. See Responsive Behaviour for more information.
Responsive behaviour
The ProgressStepper
package contains a mobile variation, accessible by nominating a collapseBelow
breakpoint.
In the mobile variation, an expandable bar displays the title of the current and next steps, alongside visual indicators of progress. If a user clicks (or taps) this bar, an expanding drawer displays the stacked variation, allowing the user to navigate directly to any available step. Try clicking on the below example:
Alignment and content
When using ProgressStepper
, it should be considered as a means of both passive and active navigation by the user. As such, it is designed to sit atop its related content, or in its stacked
variation alongside the content (in a 'sticky' sidebar). Unlike Mesh's Tab component, a ProgressStepper does not include an explicit content area, so as to allow flexibility in its application. With this in mind, its position, variation and format must be consistent across the entirety of the flow to avoid user confusion or difficulty navigating between steps.
In its default (inline) state, ProgressStepper
expands horizontally to fill its parent container, with child Steps distributed equally. This is to reflect users' desire to estimate and manage their time in completing the overall task. Note that the noded progress bar does not reflect a 'real' completion figure but a coarse indicator. For this reason, content should be divided thematically and approximately equal in effort required per step.
Colors
The line and nodes within the ProgressStepper
make use of the colorDark
color selector and so should only be used on lighter backgrounds to ensure sufficient contrast. Light and white form modes as well as colorWhite
, colorNearWhite
, colorLightest
, and colorLighter
have all been tested across all brands.
Navigation
To aid in navigation, we encourage the use of Next and Previous buttons (and/or equivalents) within each step of the experience. The ProgressStepper should not be relied on as the sole means of navigating a flow - while it does allow for limited interaction, it should also function as a visual-only indicator of progress.
If a step is able to be 'skipped', an explicit means to do so should be provided. This could take the form of a 'Skip this step' button or similar means. To give a specific example, if a Step contains a carousel of product cards representing levels of Hospital cover, a card stating 'No Hospital cover' should be provided as an equivalent and valid option within that carousel.
If a flow does not require the user to complete Steps in sequence, the isGated prop can be set to false
, allowing the user to navigate freely between Steps in any order if desired. Note that in this context, any Step accessed by the user may be marked as 'complete', and as such, any inputs or interactions contained within those Steps must be regarded as non-essential to completion of the overall task.
ProgressStepper does not provide any validation markers to highlight Steps with missed or invalid inputs, so input validation should be applied in real-time or via Next (or equivalent) buttons in each step. It's also critical that user inputs are saved when navigating via the ProgressStepper, to avoid frustration caused by loss of data.
Titling & overflow behaviours
Titles that exceed the width of their container (set via the fill prop or preset max-width) will wrap to a maximum of two lines (when inline - stacked Steps are limited to a single line). For this reason, Step
titles should be concise and indicative of the purpose or theme of each step.
When the fill
props are set to false
, Steps will hug their titles (up to a preset max-width, with wrapping behaviour as above). Note that this may cause variable distances between progress nodes, which can subtly impact a user's perception of progress and the distribution of effort required to complete a task.
In the mobile variation, a stacked
list of Steps is housed within a drawer accessed via tapping the ProgressStepper header. If the number of steps exceeds the available vertical space, the list will become scrollable within the drawer.
Development
- Use
button
ascomponent
prop, if url doesnot change while navigating through the stepper. - For Next/Gatsby applications, pass
Link
ascomponent
component for the url navigation. - It is suggested to have state management if the stepper involves
disabled
step or if involves removing/adding steps dynamically.
Titling is key
To ensure a user's recognition of individual steps' purpose, and their ability to navigate between them, concise and communicative titles are key.
Due to overflow behaviours in some contexts, titles longer than one or two words should have their intent communicated as early as possible in the title. This ensures that, if truncated, the title still communicates its purpose.
Playroom
Please note that due to technical constraints, interactivity in Playroom is limited for the ProgressStepper component. As such, it should be used only for visual approximation purposes.