Design Tokens for Mesh have just been released!
Skip to content

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.


npm install @nib/progress-stepper

Note: You will also need to install the peerDependencies @nib/icons and @nib-components/theme.


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 hook
const {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




steps (required)Step TypeThis is the heart of the ProgressStepper. It contains individual states and attributes for each Step according to an expected shape.
alignstringinlineSelects between horizontally or vertically aligned variations of ProgressStepper. Accepted values are stacked or inline.
fillbooleantrueSets the ProgressStepper to fill its parent container. When false, each contained Step will hug to the width of its respective title.
showIconsbooleantrueTop level prop to show or hide icons. If icons are not defined for all configured steps, this prop will have no effect.
isGatedbooleantrueToggles the behaviour where future steps are disabled by default. See [isGated](#isGated & isDisabled)
collapseBelowstringBreakpoint at which ProgressStepper collapses down to its interactive mobile variant. If not specified, ProgressStepper will not collapse.
stepWidthstringNominates a consistent width to be applied to all steps. Only applies if the fill prop is set to false.
currentStep (required)numberIndicates the current/active step index.
goToStepfunctionAccepts the step index as input. This function will set the indicated step as active.

Step Type

title (required)stringTitle of the step.
iconcomponentAn 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.
hrefstringNominates the target url for when the step is clicked.
isAccessed (required)booleanMarks the step as having been accessed by the user.
isDisabled (required)booleanMarks the step as presently inaccessible to the user, pending other actions or conditions.
isComplete (required)booleanMarks 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.
componentcomponentaThe component of the step. For example a NextLink component.


This is a custom hook which is exported as part of the @nib/progress-stepper package.

Input arguments

steps (required)Step TypeThis is the heart of the ProgressStepper. It contains individual states and attributes for each Step according to an expected shape.
currentStep (required)numberIndicates the initial active step index.

Returned arguments

currentStepnumberIndicates the active step index.
stepsStep TypeReturns the steps and their respective states
goToNextStepfunctionThis function will help to proceed to next step. State changes are handled by hook.
goToPreviousStepfunctionThis function will help to proceed to previous step. State changes are handled by hook.
goToStepfunctionTakes the step index as input. This function will make the indicated step as active
setStepsfunctionIf 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.


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.


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.


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.


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.


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.

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.


  • Use button as component prop, if url doesnot change while navigating through the stepper.
  • For Next/Gatsby applications, pass Link as component 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.


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.