- Upgrading from v1
- The Problem
- The Solution
- Hooks API
- Render Props API
- Step
- Routing
- Examples
- Contributors
hasBeenActive
is now false on first render. To achieve the previous behavior you can modify your code tohasBeenActive || isActive
maxVisitedStepIndex
has been renamed tomaxActivatedStepIndex
and will not include the currently active step if it's first rendered. To achieve the previous behavior you can modify your code toMath.max(maxActivatedStepIndex, activeStepIndex)
You need to implement a wizard / stepper, but have specific UI requirements. You want a flexible solution that suits a wide range of use cases. Check out the examples to see what's possible.
React Wizard Primitive handles the state management and you bring the UI. Leverage a render props or hooks API to get rid of the tedious boilerplate. You can use this library to build other abstractions, that better suit your specific needs on top of it.
The library comes with a render props and hooks API. It's written in TypeScript so you get first level type support.
Install the library with
npm install --save react-wizard-primitive
import useWizard for the hooks API.
import { useWizard } from "react-wizard-primitive";
or Wizard and WizardStep for the render props API.
import { Wizard, WizardStep } from "react-wizard-primitive";
You can optionally pass an UseWizardProps
into the hooks.
number
Sets the activeStepIndex
to the given index. All previous steps will be treated as if they've been already activated.
function({newStepIndex : number, previousStepIndex: number, maxActivatedStepIndex : number})
Is called every time the wizard step changes.
The useWizard API returns the state and a set of helper functions.
number
Currently active step
number
Index of the furthest step, that has been activated
function
Call this to proceed to the next step
function
Call this to proceed to the previous step
function(stepIndex : number)
Move to step with index stepIndex
function(stepIndex : number)
Move to step with index stepIndex. Set hasBeenActive for all following steps as well as the new step to false.
function(options?) : Step
Returns state for the current Step. This needs to be called for each wizard step you want to render. First call will return information about the first step, second call about the second, etc.
It accepts an optional options object, which takes a string routeTitle in. See Routing for further information.
const wizard = useWizard();
const step1 = wizard.getStep();
const step2 = wizard.getStep();
const step3 = wizard.getStep();
return (
<div>
{step1.isActive && <div onClick={step1.nextStep}>Step 1</div>}
{step2.isActive && <div onClick={step2.nextStep}>Step 2</div>}
{step3.isActive && <div onClick={step3.nextStep}>Step 3</div>}
</div>
);
Component
The Wizard component uses useWizard internally and exposes a compound components API via Context. Use this as a top level component for the wizard and put any number of WizardSteps in it.
You can optionally provide a render prop, which gets passed the same values that useWizard returns.
number
Sets the activeStepIndex
to the given index. All previous steps will be treated as if they've been already activated.
function({newStepIndex : number, previousStepIndex: number, maxActivatedStepIndex : number})
Is called every time the wizard step changes.
Component
The WizardStep component exposed a render props API and passes a Step to it. The step index is determined by the order in the source code.
It takes an optional string routeTitle as a prop. See Routing for further information.
<Wizard>
<WizardStep>
{({ isActive, nextStep }) =>
isActive && <div onClick={nextStep}>Step 1</div>
}
</WizardStep>
<WizardStep>
{({ isActive, nextStep }) =>
isActive && <div onClick={nextStep}>Step 2</div>
}
</WizardStep>
<WizardStep>
{({ isActive, nextStep }) =>
isActive && <div onClick={nextStep}>Step 3</div>
}
</WizardStep>
</Wizard>
or with render props:
<Wizard>
{({ activeStepIndex }) => (
<div>
Active Step is: {activeStepIndex}
<WizardStep>
{({ isActive, nextStep }) =>
isActive && <div onClick={nextStep}>Step 1</div>
}
</WizardStep>
<WizardStep>
{({ isActive, nextStep }) =>
isActive && <div onClick={nextStep}>Step 2</div>
}
</WizardStep>
<WizardStep>{({ isActive, nextStep }) => isActive && <div onClick={nextStep}>Step 3</div>}</WizardStep>
</div>
)}
</Wizard>
A step is the main data structure for the wizard. It contains the following information:
number
The index of the current step
boolean
Is the state the currently active one?
boolean
Has the step been active before?
function
Move to the step after this step.
function
Move to the step before this step.
function
Set this step to be currently active. Set hasBeenActive for all following steps to false.
function
Set this step to be currently active. All following steps will keep the activated state.
Out of the box react-wizard-primitive supports an opt-in routing via hash.
In order to use it, you need to specify a routeTitle in the getStep call or pass it as a prop to the WizardStep. The routeTitle will be used as the hash.
If no routeTitle is provided, react-wizard-primitive won't make any changes to the URL. If only some steps are provided with a title, we assume that this happened by mistake, and won't change the url either. Instead we log a warning to the console, indicating which steps are missing a title.
If a hash is present when the wizard is first rendered, it will try to find a matching step to that hash and jump to it or otherwise jump to the initial step.
You can use this behaviour to start the wizard at any given point.
<Wizard>
{"yourdomain.com/#/first-step"}
<WizardStep routeTitle="first-step">
{({ isActive, nextStep }) =>
isActive && <div onClick={nextStep}>Step 1</div>
}
</WizardStep>
{"yourdomain.com/#/second-step"}
<WizardStep routeTitle="second-step">
{({ isActive, nextStep }) =>
isActive && <div onClick={nextStep}>Step 2</div>
}
</WizardStep>
{"yourdomain.com/#/third-step"}
<WizardStep routeTitle="third-step">
{({ isActive, nextStep }) =>
isActive && <div onClick={nextStep}>Step 3</div>
}
</WizardStep>
</Wizard>
You can build nearly anything on top of react-wizard-primitive. Take a look at those examples to get an idea of what's possible.
This is a good starting point, if you want to see a basic hook implementation. A classical wizard, which displays the steps one after the other.
Same example, but implemented with the render props API.
This example demonstrates, how you can build a wizard that displays the steps one after another, but keeps the already displayed steps around.
It can get tedious to work with the basic building blocks and repeat styling or display handling all over again. This example demonstrates how you can build your own abstractions on top of react-wizard-primitive.
<MyCustomWizard>
<MyCustomWizard.Step>
<TextFields />
</MyCustomWizard.Step>
<MyCustomWizard.Step>
<div>Just some other inline jsx</div>
</MyCustomWizard.Step>
<MyCustomWizard.Step>
<div>And another one</div>
</MyCustomWizard.Step>
<MyCustomWizard.Step>
<div>Last one</div>
</MyCustomWizard.Step>
</MyCustomWizard>
Johannes Kling π» π π€ π‘ |
Jose Miguel Bejarano π€ |
kaYcee π€ |