Stepper
Examples
(6)Properties
(11)Playground
Controlled Flow
Loading demo…
import
{
useState
}
from
'react'
;
import
{
Button
,
Card
,
Block
,
Row
,
Stepper
,
Text
}
from
'@platform-blocks/react-ui-library'
;
import
{
onboardingSteps as steps
}
from
'../data'
;
const
totalSteps
=
steps
.
length
;
export
function
Demo
(
)
{
const
[
activeStep
,
setActiveStep
]
=
useState
(
1
)
;
const
handleStepChange
=
(
nextIndex
:
number
)
=>
{
if
(
nextIndex
<
0
||
nextIndex
>
totalSteps
)
{
return
;
}
setActiveStep
(
nextIndex
)
;
}
;
const
goPrevious
=
(
)
=>
handleStepChange
(
activeStep
-
1
)
;
const
goNext
=
(
)
=>
handleStepChange
(
activeStep
+
1
)
;
return
(
<Block
fullWidth
>
<Card
p
=
"md"
>
<Block
>
<Text
size
=
"sm"
color
=
"secondary"
>
Control
the current step with the
`active`
prop and provide completion content with
`Stepper.Completed`
.
</Text
>
<Stepper
active
=
{
activeStep
}
onStepClick
=
{
handleStepChange
}
>
{
steps
.
map
(
(
step
)
=>
(
<Stepper.Step
key
=
{
step
.
label
}
label
=
{
step
.
label
}
description
=
{
step
.
description
}
>
{
step
.
details
}
</Stepper.Step
>
)
)
}
<Stepper.Completed
>
All
onboarding tasks are complete
.
You
can
continue
to the dashboard
.
</Stepper.Completed
>
</Stepper
>
<Row
gap
=
"sm"
justify
=
"space-between"
>
<Button
variant
=
"outline"
onPress
=
{
goPrevious
}
disabled
=
{
activeStep
===
0
}
>
Back
</Button
>
<Button
onPress
=
{
goNext
}
disabled
=
{
activeStep
===
totalSteps
}
>
{
activeStep
===
totalSteps
-
1
?
'Finish'
:
'Next step'
}
</Button
>
</Row
>
</Block
>
</Card
>
</Block
>
)
;
}
Visited Step Selection
allowStepSelect, while preserving forward progress through the flow.Loading demo…
import
{
useState
}
from
'react'
;
import
{
Button
,
Card
,
Block
,
Row
,
Stepper
,
Text
}
from
'@platform-blocks/react-ui-library'
;
import
{
onboardingSteps as steps
}
from
'../data'
;
const
totalSteps
=
steps
.
length
;
export
function
Demo
(
)
{
const
[
activeStep
,
setActiveStep
]
=
useState
(
0
)
;
const
[
highestVisitedStep
,
setHighestVisitedStep
]
=
useState
(
0
)
;
const
handleStepChange
=
(
nextIndex
:
number
)
=>
{
if
(
nextIndex
<
0
||
nextIndex
>
totalSteps
)
{
return
;
}
setActiveStep
(
nextIndex
)
;
setHighestVisitedStep
(
(
previous
)
=>
Math
.
max
(
previous
,
Math
.
min
(
nextIndex
,
totalSteps
-
1
)
)
)
;
}
;
const
canSelectStep
=
(
stepIndex
:
number
)
=>
highestVisitedStep
>=
stepIndex
&&
activeStep
!==
stepIndex
;
const
goPrevious
=
(
)
=>
handleStepChange
(
activeStep
-
1
)
;
const
goNext
=
(
)
=>
handleStepChange
(
activeStep
+
1
)
;
return
(
<Block
fullWidth
>
<Card
p
=
"md"
>
<Block
>
<Text
size
=
"sm"
color
=
"secondary"
>
Gate
step selection with
`allowStepSelect`
so people can revisit completed steps without skipping ahead
.
</Text
>
<Stepper
active
=
{
activeStep
}
onStepClick
=
{
handleStepChange
}
>
{
steps
.
map
(
(
step
,
index
)
=>
(
<Stepper.Step
key
=
{
step
.
label
}
label
=
{
step
.
label
}
description
=
{
step
.
description
}
allowStepSelect
=
{
canSelectStep
(
index
)
}
>
{
step
.
details
}
</Stepper.Step
>
)
)
}
<Stepper.Completed
>
Setup
is complete
.
You
can always
return
to earlier steps
from
the navigation
.
</Stepper.Completed
>
</Stepper
>
<Row
gap
=
"sm"
justify
=
"space-between"
>
<Button
variant
=
"outline"
onPress
=
{
goPrevious
}
disabled
=
{
activeStep
===
0
}
>
Back
</Button
>
<Button
onPress
=
{
goNext
}
disabled
=
{
activeStep
===
totalSteps
}
>
{
activeStep
===
totalSteps
-
1
?
'Finish'
:
'Next step'
}
</Button
>
</Row
>
</Block
>
</Card
>
</Block
>
)
;
}
Icon Overrides
Loading demo…
import
{
useState
}
from
'react'
;
import
{
Button
,
Card
,
Block
,
Icon
,
Row
,
Stepper
,
Text
}
from
'@platform-blocks/react-ui-library'
;
import
{
onboardingSteps as steps
}
from
'../data'
;
const
totalSteps
=
steps
.
length
;
export
function
Demo
(
)
{
const
[
activeStep
,
setActiveStep
]
=
useState
(
1
)
;
const
handleStepChange
=
(
nextIndex
:
number
)
=>
{
if
(
nextIndex
<
0
||
nextIndex
>
totalSteps
)
{
return
;
}
setActiveStep
(
nextIndex
)
;
}
;
const
goPrevious
=
(
)
=>
handleStepChange
(
activeStep
-
1
)
;
const
goNext
=
(
)
=>
handleStepChange
(
activeStep
+
1
)
;
return
(
<Block
fullWidth
>
<Card
p
=
"md"
>
<Block
>
<Text
size
=
"sm"
color
=
"secondary"
>
Provide
`icon`
and
`completedIcon`
overrides to visually align each step with its stage
.
</Text
>
<Stepper
active
=
{
activeStep
}
onStepClick
=
{
handleStepChange
}
completedIcon
=
{
<Icon
name
=
"check"
size
=
{
18
}
color
=
"white"
/>
}
>
{
steps
.
map
(
(
step
)
=>
(
<Stepper.Step
key
=
{
step
.
label
}
label
=
{
step
.
label
}
description
=
{
step
.
description
}
icon
=
{
<Icon
name
=
{
step
.
icon
}
size
=
{
18
}
/>
}
>
{
step
.
details
}
</Stepper.Step
>
)
)
}
<Stepper.Completed
>
All
setup tasks are complete with custom indicators
for
each stage
.
</Stepper.Completed
>
</Stepper
>
<Row
gap
=
"sm"
justify
=
"space-between"
>
<Button
variant
=
"outline"
onPress
=
{
goPrevious
}
disabled
=
{
activeStep
===
0
}
>
Back
</Button
>
<Button
onPress
=
{
goNext
}
disabled
=
{
activeStep
===
totalSteps
}
>
{
activeStep
===
totalSteps
-
1
?
'Finish'
:
'Next step'
}
</Button
>
</Row
>
</Block
>
</Card
>
</Block
>
)
;
}
Vertical Orientation
Loading demo…
import
{
useState
}
from
'react'
;
import
{
Block
,
Button
,
Card
,
Row
,
Stepper
,
Text
}
from
'@platform-blocks/react-ui-library'
;
import
{
onboardingSteps as steps
}
from
'../data'
;
const
totalSteps
=
steps
.
length
;
export
function
Demo
(
)
{
const
[
activeStep
,
setActiveStep
]
=
useState
(
1
)
;
const
handleStepChange
=
(
nextIndex
:
number
)
=>
{
if
(
nextIndex
<
0
||
nextIndex
>=
totalSteps
)
{
return
;
}
setActiveStep
(
nextIndex
)
;
}
;
const
goPrevious
=
(
)
=>
handleStepChange
(
activeStep
-
1
)
;
const
goNext
=
(
)
=>
handleStepChange
(
activeStep
+
1
)
;
return
(
<Card
p
=
"md"
>
<Block
>
<Text
size
=
"sm"
color
=
"secondary"
>
Switch
to
`orientation="vertical"`
when steps need additional room
for
supporting copy
.
</Text
>
<Stepper
active
=
{
activeStep
}
onStepClick
=
{
handleStepChange
}
orientation
=
"vertical"
>
{
steps
.
map
(
(
step
,
index
)
=>
(
<Stepper.Step
key
=
{
step
.
label
}
label
=
{
step
.
label
}
description
=
{
step
.
description
}
>
{
step
.
details
}
</Stepper.Step
>
)
)
}
</Stepper
>
<Row
gap
=
"sm"
justify
=
"space-between"
>
<Button
variant
=
"outline"
onPress
=
{
goPrevious
}
disabled
=
{
activeStep
===
0
}
>
Back
</Button
>
<Button
onPress
=
{
goNext
}
disabled
=
{
activeStep
===
totalSteps
-
1
}
>
Next
step
</Button
>
</Row
>
</Block
>
</Card
>
)
;
}
Loading Indicator
loading prop.Loading demo…
import
{
useEffect
,
useRef
,
useState
}
from
'react'
;
import
{
Button
,
Card
,
Block
,
Row
,
Stepper
,
Text
}
from
'@platform-blocks/react-ui-library'
;
const
totalSteps
=
3
;
export
function
Demo
(
)
{
const
[
activeStep
,
setActiveStep
]
=
useState
(
1
)
;
const
[
isLoading
,
setIsLoading
]
=
useState
(
false
)
;
const
timeoutRef
=
useRef
<ReturnType
<
typeof setTimeout
>
|
null
>
(
null
)
;
const
handleStepChange
=
(
nextIndex
:
number
)
=>
{
if
(
nextIndex
<
0
||
nextIndex
>=
totalSteps
)
{
return
;
}
setActiveStep
(
nextIndex
)
;
}
;
const
simulateProcessing
=
(
)
=>
{
if
(
timeoutRef
.
current
)
{
clearTimeout
(
timeoutRef
.
current
)
;
}
setIsLoading
(
true
)
;
timeoutRef
.
current
=
setTimeout
(
(
)
=>
{
setIsLoading
(
false
)
;
handleStepChange
(
2
)
;
}
,
2000
)
;
}
;
useEffect
(
(
)
=>
(
)
=>
{
if
(
timeoutRef
.
current
)
{
clearTimeout
(
timeoutRef
.
current
)
;
}
}
,
[
]
)
;
return
(
<Block
fullWidth
>
<Card
p
=
"md"
>
<Block
>
<Text
size
=
"sm"
color
=
"secondary"
>
Apply
the
`loading`
prop to a step when a background task is running to replace the icon with a spinner
.
</Text
>
<Stepper
active
=
{
activeStep
}
onStepClick
=
{
handleStepChange
}
>
<Stepper.Step
label
=
"Collect details"
description
=
"Complete form"
>
Share
your project information to kick off the workflow
.
</Stepper.Step
>
<Stepper.Step
label
=
"Processing"
description
=
"Sync data"
loading
=
{
isLoading
}
>
We
are syncing your data and preparing the workspace
.
</Stepper.Step
>
<Stepper.Step
label
=
"Ready"
description
=
"Launch"
>
Setup
is complete and the workspace is ready
for
collaborators
.
</Stepper.Step
>
</Stepper
>
<Row
justify
=
"center"
>
<Button
onPress
=
{
simulateProcessing
}
disabled
=
{
isLoading
}
>
{
isLoading
?
'Processing...'
:
'Simulate processing'
}
</Button
>
</Row
>
</Block
>
</Card
>
</Block
>
)
;
}
Size Variants
size prop across the full xs–3xl scale while reusing the same steps.Loading demo…
import
{
Block
,
Stepper
,
Text
}
from
'@platform-blocks/react-ui-library'
;
const
SIZES
=
[
'xs'
,
'sm'
,
'md'
,
'lg'
,
'xl'
,
'2xl'
,
'3xl'
]
as
const
;
export
function
Demo
(
)
{
return
(
<Block
fullWidth
>
{
SIZES
.
map
(
(
size
)
=>
(
<Block
key
=
{
size
}
fullWidth
>
<Text
variant
=
"small"
color
=
"secondary"
>
{
size
}
</Text
>
<Stepper
active
=
{
1
}
size
=
{
size
}
>
<Stepper.Step
label
=
"Plan"
/>
<Stepper.Step
label
=
"Build"
/>
<Stepper.Step
label
=
"Launch"
/>
</Stepper
>
</Block
>
)
)
}
</Block
>
)
;
}
</>
react-ui-library
100+ accessible, themeable components that work seamlessly across iOS, Android, and Web.
A Platform Blocks product.
Quick Links
Resources