use-steps
A simple abstraction for complex stepped flows.
npm i use-steps --save
Usage
use-steps
only provides logic and (optionally) handles animation timing. You
need to bring your own UI.
import React from 'react'
import { useSteps, Step as StepProps } from 'use-steps'
enum StepIds {
ONE = 'one',
TWO = 'two',
THREE = 'three',
FOUR = 'four',
}
/**
* These props can be anything, and allow you to type arbitrary data and add it
* to each step object below.
*/
type StepProps = {
component: React.ReactNode
}
function Step({ id, active, valid, next, prev, goTo, goPrev, goNext }: StepProps) {
// maybe handle animations here
return <div>You're on step: {id}</div>
}
function Steps(props) {
const [activeStep, setActiveStep] = React.useState(StepIds.ONE)
const { steps, goTo, goNext, goPrev } = useSteps({
activeStepId: activeStep,
activeStepIdSet: setActiveStep,
steps: [
{
id: StepIds.ONE,
next() {
return props.someValue ? StepIds.TWO : StepIds.THREE
},
// define different components for each step if you want
component: Step,
},
{
id: StepIds.TWO,
valid() {
// guard against reaching this step
return props.someValue ? true : false
},
prev() {
return StepIds.ONE
},
next() {
return StepIds.THREE
},
component: Step,
},
{
id: StepIds.THREE,
prev() {
// conditionally set steps
return props.someValue ? StepIds.TWO : StepIds.ONE
},
next() {
return StepIds.FOUR
},
component: Step,
},
{
id: StepIds.FOUR,
prev() {
return StepIds.THREE
},
component: Step,
},
],
})
return (
<>
{steps.map((props) => (
<step.component key={props.id} {...props} />
))}
<button onClick={goPrev}>Prev</button>
<button onClick={goNext}>Next</button>
</>
)
}
Animation
use-steps
can help with animations as well. If you provide an animationSpeed
value, the library will stagger the value of active
to provide time for you
to animate your screens in and out. Then, you'll want to use something like
react-transition-group
or mounty to handle animations.
Here's an example with mounty
. Here, you would provide animations styles to
.step
and .is-active
.
import cx from 'classnames'
import { Mounty } from 'mounty'
const animationSpeed = 300 // 300ms
function Steps(props) {
const [activeStep, setActiveStep] = React.useState(StepIds.ONE)
const stepper = useSteps({
animationSpeed,
activeStepId: activeStep,
activeStepIdSet: setActiveStep,
steps: [...]
})
return (
<>
{steps.map(step => (
<Mounty key={step.id} in={step.active} timeout={animationSpeed} shouldUnmount>
{state => {
return (
<div className={cx('step', {
'is-visible': state.ready || state.entering || state.entered
})}>
{children}
</div>
);
}}
</Mounty>
))}
</>
)
}
License
MIT License © Truework