Examples
Wizard example
This example shows a simple Wizard component with the following features:
- Three different tabs
- Navigation using Next and Previous buttons
- Validation of data before navigating away from the first page
- A cancel option that redirects the user to the second page
- A simple progress bar
The following sections explain the different steps to define a basic Wizard using the components from the @jutro/wizard-next
package.
The Wizard implementation requires:
- Definition of the different Wizard pages that can be displayed
- Definition of the Wizard layout: how the wizard is displayed, including breakpoint alternatives
- Definition of the custom elements like the action bar and progress indicator
- Definition of the Wizard steps: routes and alternatives, for example where the user is directed after completing a step
- The composition of the Wizard by using all the previously defined elements
1. Define the wizard pages
Defining a wrapper component is the recommended approach for the Wizard pages definition. Each Wizard step must reference a component that either wraps or extends WizardPage
.
The following example shows how to create the page components for the above Wizard.
import { useState } from 'react';
import { WizardPage } from '@jutro/wizard-next';
import { Checkbox } from '@jutro/components';
import { useLocation } from 'react-router-dom';
const TheFirstPage = ({ id, wizardPageProps }) => {
const location = useLocation();
const [valid, setValid] = useState(false);
const [stateMessages, setStateMessages] = useState(null);
const firstStepCheckboxChanged = (e, value) => {
setValid(value);
};
const wizardPageOnNext = () => {
if (!valid) {
setStateMessages({
error: ['Select this checkbox to go to the next page'],
});
}
return valid;
};
return (
<WizardPage
id={id}
{...wizardPageProps}
onNext={wizardPageOnNext}
location={location}
title="First page">
<span>Here you can add your content</span>
<Checkbox
label="This is mandatory to continue"
required={true}
stateMessages={stateMessages}
onChange={firstStepCheckboxChanged}
/>
</WizardPage>
);
};
const AnotherWizardPage = ({ id, wizardPageProps }) => {
const location = useLocation();
return (
<WizardPage
id={id}
{...wizardPageProps}
location={location}
title="Second page">
<span>Another wizard page</span>
</WizardPage>
);
};
const LastWizardPage = ({ id, wizardPageProps }) => {
const location = useLocation();
return (
<WizardPage
id={id}
{...wizardPageProps}
location={location}
title="The last page">
<span>The last wizard page</span>
</WizardPage>
);
};
Apart from the page definition, the example has a validation mechanism implemented for the first page which, in case of invalid data, prevents the transition to the next page.
2. Define the layout
Define the Wizard page structure for the different breakpoints.
const layout = {
desktop: { colStart: 1, colSpan: 12 },
tablet: { colStart: 1, colSpan: 10 },
phone: { colStart: 1, colSpan: 6 },
};
3. Define any custom elements
In this example, we are using components from the base configuration. See the Customizing the progress bar and Customizing the action bar sections for custom implementation references.
4. Define the wizard steps
You must specify the corresponding route and the assigned WizardPage
component for each step.
const steps = [
{
id: 'wizard.firstpage',
route: 'firstpage',
title: 'First page',
component: TheFirstPage,
},
{
id: 'wizard.secondpage',
route: 'secondpage',
title: 'Second page',
component: AnotherWizardPage,
},
{
id: 'wizard.lastpage',
route: 'lastpage',
title: 'Last page',
component: LastWizardPage,
},
];
5. Compose the wizard
Bring all the elements defined so far together to compose the wizard.
The Cancel option is added by defining a cancelPath
property, while the Next and Previous buttons use the steps definition order by default.
import { Wizard } from '@jutro/wizard-next';
import { useLocation } from 'react-router-dom';
<Wizard
layout={layout}
baseRoute={'/'}
basePath={'/'}
location={useLocation}
cancelPath="secondpage"
steps={steps}
/>;
Customizing the progress bar
Use renderProgressBar
to turn off the progress bar, or render a custom progress bar.
- To turn off the progress bar, set
renderProgressBar
to null
or false
.
- To customize the progress bar, set
renderProgressBar
to a render prop.
This render prop expects a function that receives one parameter, an object with the basePath
prop and an array of the steps
which are both passed to the Wizard.
The following is an example of a custom progress bar made using the layout and steps defined in the previous examples:
import { useLocation } from 'react-router-dom';
import { Wizard } from '@jutro/wizard-next';
import { StepProgressBar } from '@jutro/components';
const customProgressBar = ({ basePath, steps }) => {
const { pathname } = useLocation();
const stepRoutes = steps.map((step) => step?.route);
const currentStep = stepRoutes.indexOf(pathname.replace(`${basePath}/`, ''));
const barSteps = steps.map((step) => {
step.active = false;
return step;
});
if (currentStep >= 0) barSteps[currentStep].active = true;
return <StepProgressBar steps={barSteps} />;
};
<Wizard
layout={layout}
baseRoute={'/'}
basePath={'/'}
location={useLocation}
cancelPath="firstpage"
steps={steps}
renderProgressBar={customProgressBar}
/>;
For more information about render props, see the React docs.
Customizing the action bar
Use renderActionBar
to disable the action bar, or render a custom action bar.
- To disable the action bar, set
renderActionBar
to null
or false
.
- To customize the action bar, set
renderActionBar
to a render prop.
The render prop is a function that receives two parameters:
resolvedPropsForButtons
- this includes route paths which are calculated by the Wizard based on the flow and the current step.
actionBarLayout
- the same prop passed into Wizard to set the layout of the action bar. If you are using a custom action bar, you can use this prop in any way you want, as it is passed directly through the Wizard to the render prop function.
An example of a custom action bar, using the steps and layout from previous examples would be:
export const WizardWithCustomActionBar = () => {
const location = useLocation();
const history = useHistory();
const customActionBar = (resolvedPropsForButtons, actionBarLayout) => {
const selectedFlexDirection =
actionBarLayout === 'column' ? 'column' : 'row';
return (
<div
style={{
border: 'solid 1px yellow',
display: 'flex',
flexDirection: selectedFlexDirection,
}}>
{resolvedPropsForButtons.map((propForButton) =>
('next' == propForButton.name || 'previous' == propForButton.name) &&
propForButton.to != undefined ? (
<Button
label={propForButton.name}
fullWidth={true}
onClick={(e, to: propForButton.to) => handleNavigation(e, to)}
/>
) : (
''
)
)}
</div>
);
};
const handleNavigation = (event, to) => {
history.replace(`//${to}`);
};
return (
<Wizard
layout={layout}
baseRoute={'/'}
basePath={'/'}
location={location}
steps={steps}
renderActionBar={customActionBar}
/>
);
};
We have removed the validation from this example, but you can add it in the handleNavigation
function.
Code
Import statement
import { * } from '@jutro/wizard-next';
Jutro provides the Wizard related features through the @jutro/wizard-next
package. It contains the following components:
Wizard
WizardPage
WizardProgress
WizardActionBar
WizardPrompt
The Wizard
is the main component that puts all the pieces together - the progress bar, the buttons and actions associated with them, and the wizard content in the wizard pages. When using WizardProgress
and WizardActionBar
, you can customize their look and feel, use your own components in them, or remove them completely.
Wizard features
The main features of the Wizard are:
Progress indicator
Apart from the default progress indicator provided, it is possible to use a custom one. This enables you to create your own progress indicator to meet your project requirements, while fully utilizing the other Jutro Wizard features.
Action bar
The action bar manages the wizard actions. It supports onCancel
, onFinish
, onNext
, and onPrevious
events and the associated callbacks can be customized using JSX. Additionally, you can customize a knockout page for each action. Within each action, you can customize a different knockout page depending on the response.
Page transitions
Manages the page transitions, normally triggered by the user through the action bar buttons interaction. Supports next
, previous
, and jump
(for example, a user is on step 5 and the jump action takes them to step 3).
The Wizard engine does not enforce a re-validation when the user changes the data after jumping to a previous step. This is an implementation/project concern.
Wizard component
Use this component to render a wizard. This component is the main wizard container. It renders routes for the specified steps. Each step must reference a component that either wraps or extends <WizardPage
. Each step component will receive information from the wizard and navigation paths to be used in page rendering.
import { Wizard } from '@jutro/wizard-next';
const steps = [
{
key: 'one',
route: 'step1',
component: PageOne,
},
{
key: 'two',
route: 'step2',
component: PageTwo,
},
{
key: 'three',
route: 'step3',
component: PageThree,
},
];
<Wizard
baseRoute="/wizard/:zipCode"
basePath="/wizard/90210"
steps={steps}
cancelPath="/home"
finishPath="/home"
/>;
Wizard props
This is the list of properties of the Wizard
component. In the next subsections you can find additional information of the layout
and buttonProps
properties and their expected types.
basePath
required
DescriptionBase path for the wizard; used when building step links
baseRoute
required
DescriptionBase route for the wizard; used when building step routes
location
required
actionBarLayout
Type'default' | 'spaceEvenly'
DescriptionThe type of layout applied to action bar items: default
- keeps items with visual separation, spaceEvenly
- distributes items evenly in available grid space
bodyClassName
DescriptionCSS class name for the body of this component
Type{ cancel:{}, previous: {}, next: {}, finish: {} }
DescriptionOverrides for action buttons
callbackMap
Type{onStartWizard: func, onFinishWizard: func, onCancelWizard: func,}
DescriptionCallback map for the resolver
cancelPath
DescriptionPath to navigate on 'cancel'; if none provided, the 'cancel' button will not be displayed
className
DescriptionCSS class name for this component
componentMap
DescriptionComponent map for page component resolver
finishPath
DescriptionPath to navigate on 'finish'; if none provided, the 'finish' button will not be displayed
history
initialStepPath
DescriptionPath to the initial step (will be appended to 'basePath'); if not provided, the first step will be displayed
knockoutPath
DescriptionPath to navigate on fail of 'next'; if none provided, no default failTo will be added to the 'next' button
layout
Type{desktop: layoutShape, tablet: layoutShape, phoneWide: layoutShape, phone: layoutShape}
DescriptionObject to override page layout
match
onCancel
DescriptionCallback to invoke when the 'cancel' button is clicked; returns true, false or a promise
onFinish
DescriptionCallback to invoke when the 'finish' button is clicked; returns true, false or a promise
onStart
DescriptionCallback to trigger when the Wizard mounts
onWizardEvent
Typefunc(info, eventName)
DescriptionThe function(info, eventName) called when a page loads (invoked by WizardPage)
renderActionBar
DescriptionCallback to render the action bar, or hide/show it
renderNotFound
DescriptionCallback to render 'not found' content; if not provided, nothing will be rendered if a path is not found
renderProgressBar
DescriptionCallback to render a progress bar, or hide/show it
staticContext
DescriptionReact-Router static context
steps
Type{ id: string, route: string, title: string, , component: React.Node }[]
DescriptionArray of steps of the wizard
subRoutes
Type{ id: string, route: string, title: string, , component: React.Node }[]
DescriptionArray of routes for subwizards. If a subroute matches the current location a subwizard is active otherwise the outer wizard is active
Wizard layouts
The wizard uses a grid structure derived from the Layout
component. You can also pass custom layout objects for desktops, tablets, and phones to customize the wizard layout.
return (
<WizardExampleContext.Provider value={exampleContext}>
<Wizard
baseRoute={route}
layout={{
desktop: {
columns: ['1fr'],
repeat: '4',
gap: 'large',
colStart: '2',
colSpan: '1',
},
tablet: {
repeat: '4',
...
},
phone: {
repeat: '4',
...
},
}}
basePath={path}
steps={steps}
.......
/>
</WizardExampleContext.Provider>
);
Layout prop
children
TypeReactNode (preferably `GridItem`)
DescriptionThe content to be displayed in the page
className
DescriptionCSS class passed to grid tag
DescriptionId to identify the layout component
layout
Type{desktop?: LayoutShape, tablet?: LayoutShape, phoneWide?: LayoutShape, phone?: LayoutShape,}
colSpan
DescriptionSpecifies how many columns an element should span across.
colStart
columns
gap
Type'auto-none' | 'small' | 'medium' | 'large'
DescriptionThe gap size between rows and columns.'
repeat
Type'auto-fit' | 'auto-fill' | number
DescriptionAmount of columns to repeat.
DescriptionOverride the default device layout: desktop
, tablet
, phoneWide
and phone
, all of type LayoutShape
LayoutShape
props
The LayoutShape
object is used in the layout
property to define the layout of the wizard for each of the possible breakpoints.
colSpan
Descriptionspecifies how many columns an element should span across
colStart
Descriptiondefine column to start from
columns
gap
Type'none', 'small', 'medium', 'large'
DescriptionGap between rows and columns
repeat
Type'auto-fit' | 'auto-fill' | number | string
buttonProps
are passed to the action bar buttons. This includes cancel
, previous
, next
, and finish
. They can be used to customize the look and feel or the behavior of the default Wizard
(or WizardPage
) buttons.
You can pass button props to both Wizard
and WizardPage
.
If you set buttonProps
in the Wizard component, you override the default values of the action bar buttons for the whole wizard flow.
For example, the wizard will have a next
button with fullWidth
set to true
:
<Wizard
buttonProps={{
next: {
fullWidth: true,
},
}}
/>
If you set buttonProps
in a Wizard step, you override the values of the action bar buttons for that step.
Continuing the previous example, this step of the wizard flow would then have a next
button with fullWidth
set to false
, overwriting the value set at the wizard level for this particular step.
<WizardPage
buttonProps={{
next: {
fullWidth: false,
},
}}
/>
children
TypeReact.Node | IntlMessageShape | { pathname?: IntlMessageShape; hash?: IntlMessageShape }
DescriptionThe children elements to render inside of the Button
className
DescriptionCSS class name for this button
disabled
DescriptionIf true
this button is disabled
failToMessage
DescriptionThe message shown when the promise is rejected; shown if 'failTo' is not provided
fullWidth
DescriptionIf true
, the button expands to the available width
icon
iconClassName
DescriptionCSS class name for the icon
iconPosition
DescriptionWhere the icon is placed relative to the text
DescriptionID to be assigned to the button
message
DescriptionThe message shown when executing the trigger/promise
size
DescriptionAllows you to select the smaller or larger variant
TypeIntlMessageShape | IntlRouterLocation
DescriptionThe destination path when the promise is resolved; can be an object like <Link to>
toMessage
DescriptionThe message shown when the promise is resolved; shown if 'to' is not provided
Wizard page component
The WizardPage
component defines the content and events for a specific Wizard step.
import { WizardPage } from '@jutro/wizard-next';
import { useLocation } from 'react-router-dom';
const myWizardPage = () => {
const location = useLocation();
return (
<WizardPage
{
cancelPath="/"
finishPath="/offer"
knockoutPath="/knockoutPage"
} location={location}>
<span>Account wizard page</span>
</WizardPage>
);
};
WizardPage props
children
required
DescriptionThe content to be displayed in the page
id
required
DescriptionId passed to the page panel
location
required
DescriptionThe location object with pathname of current url. Usually provided from the location.pathname prop passed from the router.
DescriptionOverrides for action buttons
className
DescriptionCSS class passed to root element of the component
DescriptionCSS class passed to wizard page header
knockoutPath
DescriptionPath to navigate on fail of 'next'; if none is provided, no default failTo will be added to the 'next' button
onLoad
DescriptionThe callback to invoke when page is loaded; returns true, false or a promise
onNext
DescriptionThe callback to invoke when the 'next' button is clicked; returns true, false or a promise
onPageEventInfo
DescriptionThe callback to get page event info to send with a wizard event
onPrevious
DescriptionCallback to invoke when the 'back' button is clicked; returns true, false or a promise
pageEventInfo
DescriptionObject or callback to get page event info to send with a wizard event
panelClassName
DescriptionAdditional class name for the panel
DescriptionFunction which renders a custom panel header element
renderPanel
DescriptionThe callback to the render panel method; if null then renders without a panel
renderSubTitle
DescriptionFunction to render a custom subTitle
renderTitle
DescriptionFunction to render a custom title
resolveCallbackMap
DescriptionCallback map for the resolver
subTitle
DescriptionDefault panel subtitle expression
title
DescriptionDefault panel title expression
WizardPage considerations and references
Wizard progress bar component
There is a default progress indicator that you can customize or you can provide a custom component through the render function property.
The default progress indicator is managed through the WizardProgress
component. It relies on the SimpleProgressBar
component.
All the WizardProgress
component logic is based on the information provided by the Wizard
where it is embedded. For example, the list of steps is extracted from the Wizard Context.
See the Customizing the progress bar section for further details.
WizardProgress props
basePath
DescriptionPath to be used when composing the steps urls
location
Type'none' | 'small' | 'medium' | 'large'
DescriptionTo look for matching subroutes
progressBarClassName
deprecated
DescriptionClass to override progress bar step styles
Wizard action bar
The WizardActionBar
component provides the default functionality to display and handle the different options available in the Wizard. It generates and renders the WizardButton
from actions passed using props. It combines the action with default properties for each button; the default properties are overwritten when provided in actions.
Below is an example defining what happens when the user clicks the Cancel or Next button:
import { WizardActionBar } from '@jutro/wizard-next';
const actions = [
{name: 'cancel', to: '/'},
{name: 'next', to: '/wizard/test/step2'}
]
<WizardActionBar actions={actions}/>
WizardActionBar props
actions
required
DescriptionThe list of actions to be rendered in the <WizardActionBar>
className
DescriptionCSS class name for this component
layout
Type'default' | 'spaceEvenly' | 'center'
DescriptionType of layout applied to action bar items: default
- keeps items with visual separation, spaceEvenly
- distributes items evenly in available grid space, center
- center button horizontally, will vertically stack multiple buttons
Wizard prompt
Provides a convenient prompting mechanism for the context of a wizard. It allows separate conditions and prompts for 'previous' and 'cancel' windows.
import { <WizardPrompt } from '@jutro/wizard-next';
<WizardPrompt
cancelPrompt={{when: wizardChanged, message: 'Want to cancel?'}}
previousPrompt={{when: dataChanged, message: 'Want to go back?'}}
/>
WizardPrompt props
basePath
DescriptionPath to be used when composing the steps urls
previousPrompt
Type{when: boolean, title: string, message: string }
DescriptionProperties for the 'previous' prompt; contains 'when', 'title' and 'message'
cancelPrompt
deprecated
Type{when: boolean, title: string, message: string }
DescriptionProperties for the 'cancel' prompt; contains 'when', 'title' and 'message'
Wizard custom behaviors
Prevent navigation
If the function passed to the onCancel
, onNext
, or onPrevious
properties returns false
, the action is stopped, and the user is not redirected to the corresponding path, staying on the current step.