@dnb/eufemia
Version:
DNB Eufemia Design System UI Library
521 lines (462 loc) • 13.7 kB
Markdown
---
title: 'StepIndicator'
description: "The StepIndicator (progress indicator) is a visual representation of a user's progress through a set of steps or series of actions."
version: 11.0.0
generatedAt: 2026-04-21T13:57:52.941Z
checksum: 7094e7f08cf3afc69f190c375d8431006f20b457a07ad2e731e6ad137f4dbe05
---
```tsx
import { StepIndicator } from '@dnb/eufemia'
```
The step indicator (progress indicator) is a visual representation of a user's progress through a set of steps or series of actions. Their purpose is to both guide the user through the process and to help them create a mental model of the amount of time and effort that is required to fulfill the process.
## Relevant links
- [Figma](https://www.figma.com/design/cdtwQD8IJ7pTeE45U148r1/%F0%9F%92%BB-Eufemia---Web?node-id=15878-71)
- [Source code](https://github.com/dnbexperience/eufemia/tree/main/packages/dnb-eufemia/src/components/step-indicator)
- [Docs code](https://github.com/dnbexperience/eufemia/tree/main/packages/dnb-design-system-portal/src/docs/uilib/components/step-indicator)
If the user should be able to navigate back and forth, use the `mode="loose"` property. More about the modes further down.
The current active step is set with the `currentStep` property or within the data with the `isCurrent` object property.
**NB:** Whenever possible, ensure you bind the `currentStep` to the browsers path location. See the [example below](/uilib/components/step-indicator/
The mode property is mandatory. It tells the component how it should behave.
- [strict](/uilib/components/step-indicator
- [loose](/uilib/components/step-indicator
- [static](/uilib/components/step-indicator
Use `strict` for a chronological step order.
The user can navigate between the visited steps and the current step. The component keeps track of these reached steps.
Use `loose` if the user should be able to navigate freely between all steps. Also, those which are not visited before.
Use `static` for non-interactive steps.
You can easily modify a step – e.g. should one step not be interactive, you can use the `inactive` property on that step:
```js
const steps = [
{ title: 'Active' },
{ title: 'Not active', inactive: true },
]
```
More details about modifying steps in the [properties panel](/uilib/components/step-indicator/properties
Every step can be clicked.
```tsx
const InteractiveDemo = () => {
const [step, setStep] = React.useState(1)
return (
<div
style={{
display: 'flex',
}}
>
<Space stretch>
<StepIndicator
mode="loose"
currentStep={step}
onChange={({ currentStep }) => {
setStep(currentStep)
}}
data={[
'Cum odio si bolig bla et ta',
'Auctor tortor vestibulum placerat bibendum sociis aliquam nunc sed venenatis massa eget duis',
'Bibendum sociis',
]}
bottom
/>
<Button
variant="secondary"
onClick={() => {
setStep((step) => {
if (step >= 2) {
step = -1
}
return step + 1
})
}}
>
Next step
</Button>
</Space>
</div>
)
}
render(<InteractiveDemo />)
```
Every visited step can be clicked, including the current step.
```tsx
render(
<StepIndicator
mode="strict"
currentStep={1}
onChange={({ currentStep }) => {
console.log('onChange', currentStep)
}}
data={[
{
title: 'Velg mottaker',
},
{
title: 'Bestill eller erstatt',
onClick: ({ currentStep }) =>
console.log('currentStep:', currentStep),
status:
'Du må velge bestill nytt kort eller erstatt kort for å kunne fullføre bestillingen din.',
},
{
title: 'Oppsummering',
},
]}
/>
)
```
None of the steps are clickable.
```tsx
render(
<StepIndicator
mode="static"
currentStep={1}
onChange={({ currentStep }) => {
console.log('onChange', currentStep)
}}
data={[
{
title: 'Om din nye bolig',
},
{
title: 'Ditt lån og egenkapital',
onClick: ({ currentStep }) => console.log(currentStep),
},
{
title: 'Oppsummering',
},
]}
/>
)
```
```tsx
const StepIndicatorWithRouter = () => {
const [currentStep, setCurrentStep] = React.useState(1)
React.useEffect(() => {
const step =
parseFloat(window.location.search?.replace(/[?]/, '')) || 1
setCurrentStep(step)
}, [])
return (
<>
<StepIndicator
mode="loose"
currentStep={currentStep - 1}
onChange={({ currentStep }) => {
const step = currentStep + 1
setCurrentStep(step)
window.history.pushState({}, '', '?' + step)
}}
data={[
{
title: 'Om din nye bolig',
},
{
title: 'Ditt lån og egenkapital',
},
{
title: 'Oppsummering',
},
]}
/>
</>
)
}
render(<StepIndicatorWithRouter />)
```
Completely customized step indicator.
```tsx
function CustomStepIndicator({ children, data, ...props }) {
const [step, setStep] = React.useState(0)
return (
<>
<StepIndicator
mode="loose"
data={data}
currentStep={step}
onChange={({ currentStep }) => setStep(currentStep)}
bottom
{...props}
/>
<Section backgroundColor="lavender" innerSpace>
{children(step)}
</Section>
</>
)
}
render(
<CustomStepIndicator
data={[
{
title: 'First',
isCurrent: true,
},
{
title: 'Second',
},
{
title: 'Last',
},
]}
>
{(step) => {
switch (step) {
case 0:
return <>Step One</>
case 1:
return <>Step Two</>
default:
return <>Fallback</>
}
}}
</CustomStepIndicator>
)
```
This example also demonstrates the `expandedInitially` property.
```tsx
render(
<StepIndicator
expandedInitially
mode="static"
currentStep={1}
data={['Om din nye bolig', 'Ditt lån og egenkapital', 'Oppsummering']}
/>
)
```
### With skeleton
```tsx
render(
<StepIndicator
mode="static"
skeleton
currentStep={1}
expandedInitially
data={[
{
title: 'Om din nye bolig',
},
{
title: 'Ditt lån og egenkapital',
},
{
title: 'Oppsummering',
},
]}
/>
)
```
```tsx
render(
<StepIndicator
mode="loose"
currentStep={0}
data={[
{
title: 'Current',
},
{
title: 'Warning',
status: 'Status message',
statusState: 'warning',
},
{
title: 'Error',
status: 'Status message',
statusState: 'error',
},
{
title: 'Information',
status: 'Status message',
statusState: 'information',
},
]}
/>
)
```
## Properties
```json
{
"props": {
"mode": {
"doc": "Defines how the StepIndicator should work. Use `static` for non-interactive steps. Use `strict` for a chronological step order, also, the user can navigate between visited steps. Use `loose` if the user should be able to navigate freely.",
"type": ["\"static\"", "\"strict\"", "\"loose\""],
"status": "required"
},
"data": {
"doc": "Defines the data/steps showing up in a JavaScript Array or JSON format like `[{title,isCurrent}]`. See below for properties of `STEP_DATA`.",
"type": [
"Array<[Step Item](#step-item-properties)>",
"Array<string>"
],
"status": "required"
},
"currentStep": {
"doc": "Defines the initial step starting from 0. Also defines the furthest step visited when `mode=\"strict\"`. Will update to the new step if changed (but will not trigger the `onChange` event). Defaults to `0`.",
"type": "number",
"status": "optional"
},
"overviewTitle": {
"doc": "The title shown inside the `<StepIndicatorModal />` supplemental screen reader text for the `<StepIndicatorTriggerButton />`. Defaults to `Steps Overview`.",
"type": "string",
"status": "optional"
},
"stepTitle": {
"doc": "Label for `<StepIndicatorTriggerButton />` and screen reader text for `<StepIndicatorItem />`. Must contain `%step` and `%count` to interpolate `currentStep` and `stepCount` into the text. Defaults to `Step %step of %count`.",
"type": "string",
"status": "optional"
},
"hideNumbers": {
"doc": "Define whether to show automatically counted numbers or not. Defaults to `false`.",
"type": "boolean",
"status": "optional"
},
"noAnimation": {
"doc": "If set to `true`, the height animation on step change and list expansion will be omitted. Defaults to `false`.",
"type": "boolean",
"status": "optional"
},
"expandedInitially": {
"doc": "Set to `true` to have the list be expanded initially. Defaults to `false`.",
"type": "boolean",
"status": "optional"
},
"outset": {
"doc": "Whether or not to break out (using negative margins) on larger screens. Defaults to `false`. Same as `outset` in [Card](/uilib/components/card/properties).",
"type": "boolean",
"status": "optional"
},
"status": {
"doc": "Text for status shown below the step indicator when it is not expanded. Defaults to `undefined`.",
"type": "string",
"status": "optional"
},
"statusState": {
"doc": "The type of status shown when the `status` property is set. Defaults to `warning`.",
"type": ["\"warning\"", "\"information\"", "\"error\""],
"status": "optional"
},
"skeleton": {
"doc": "If set to `true`, an overlaying skeleton with animation will be shown.",
"type": "boolean",
"status": "optional"
},
"[Space](/uilib/layout/space/properties)": {
"doc": "Spacing properties like `top` or `bottom` are supported.",
"type": ["string", "object"],
"status": "optional"
}
}
}
```
```json
{
"props": {
"title": {
"doc": "The title of the step.",
"type": ["string", "React.ReactNode"],
"status": "required"
},
"isCurrent": {
"doc": "If set to `true`, this item step will be set as the current selected step. This can be used instead of `currentStep` on the main component.",
"type": "boolean",
"status": "optional"
},
"inactive": {
"doc": "If set to `true`, this item step will be handled as an inactive step and will not be clickable. Defaults to `false`.",
"type": "boolean",
"status": "optional"
},
"disabled": {
"doc": "If set to `true`, this step will be handled the same as `inactive` as well as getting a disabled mouseover and `aria-disabled=\"true`. Defaults to `false`.",
"type": "boolean",
"status": "optional"
},
"status": {
"doc": "Is used to set the status text.",
"type": ["string", "React.ReactNode"],
"status": "optional"
},
"statusState": {
"doc": "In case the status state should be `information` or `error`. Defaults to `warning`.",
"type": ["\"warning\"", "\"information\"", "\"error\""],
"status": "optional"
}
}
}
```
```js
const steps = [
{ title: 'Active' },
{ title: 'Active and marked as current', isCurrent: true },
{ title: 'Not active', inactive: true },
{ title: 'Disabled', disabled: true },
{
title: 'Active item with status text',
status: 'Status text',
statusState: 'warning', // defaults to warning
},
]
```
```json
{
"locales": ["da-DK", "en-GB", "nb-NO", "sv-SE"],
"entries": {
"StepIndicator.overviewTitle": {
"nb-NO": "Stegoversikt",
"en-GB": "Steps Overview",
"sv-SE": "Stegöversikt",
"da-DK": "Trinoverblik"
},
"StepIndicator.stepTitle": {
"nb-NO": "Steg %step av %count:",
"en-GB": "Step %step of %count:",
"sv-SE": "Steg %step av %count:",
"da-DK": "Trin %step af %count:"
}
}
}
```
```json
{
"props": {
"onClick": {
"doc": "Will be called when the user clicks on any clickable step in the list. Is called right before `onChange`. Receives parameter `{ event, item, currentStep }`.",
"type": "function",
"status": "optional"
},
"onChange": {
"doc": "Will be called when the user changes step by clicking in the steps list (changing the `currentStep` property does not trigger the event). Receives parameter `{ event, item, currentStep }`.",
"type": "function",
"status": "optional"
}
}
}
```
```json
{
"props": {
"onClick": {
"doc": "Called when user clicks the step. Is called right before the main component's `onClick`. Receives parameter `{ event, item, currentStep }`.",
"type": "function",
"status": "optional"
}
}
}
```