Wizard helper
The wizard helper makes it easy to build and iterate a ‘one thing per page’ user journey.
Importing the wizard helper
import { wizard } from 'govuk-prototype-rig'
Usage
The wizard
helper takes two parameters:
Name | Type | Description |
---|---|---|
journey | object | Required. A journey object, which defines the default user journey and any branching rules |
req | object | Required. The express request object |
It returns a paths
object with paths for the next, back and the current pages.
For the following journey:
const journey = {
'/': {},
'/name': {},
'/where-do-you-live': {},
'/nationality': {},
'/check-answers': {},
'/confirm': {}
}
wizard(journey, req)
If the request was made from /nationality
, the helper returns:
{
back: '/where-do-you-live',
current: '/nationality',
next: '/check-answers'
}
Forking a journey
By default a user will progress through the journey in the order set out.
You can fork from that journey by giving a list of paths and conditions – if the conditions are met the user will follow the fork.
{
'/path': {
// Redirect if session.data.key equals 'Some value'
'/path-to-fork-to': { data: 'key', value: 'Some value' },
// Redirect if session.data.key is in the given array
'/path-to-fork-to': { data: 'key', values: ['A value', 'Another value'] },
// Redirect if session.data.key does not equal 'Some value'
'/path-to-fork-to': { data: 'key', excludedValue: 'Some value' },
// Redirect if session.data.key is not in the given array
'/path-to-fork-to': { data: 'key', excludedValues: ['A value', 'Another value'] },
// Redirect if the given function evaluates to true
'/path-to-fork-to': () => {
return req.session.data.key == 'Something else'
},
// Shorthand
'/path-to-fork-to': () => req.session.data.key == 'Something else',
// Always redirect
'/path-to-fork-to': true
}
}
Each path can have multiple forks, they are evaluated in order – the user will be redirected to the first page that meets the conditions.
{
// Go to different pages based on the country chosen
'/pick-a-country': {
'/scotland': { data: 'country', value: 'Scotland' },
'/wales': { data: 'country', value: 'Wales' },
'/ireland': { data: 'country', values: ['Ireland', 'Northern Ireland'] },
'/asia': () => isCountryInAsia(req.session.data.country),
'/other-countries': true
}
}
An example
In this example we:
- ask the user their name
- ask if they have a National Insurance number, then:
- skip the ‘What is your National Insurance number?’ question if they do not have a number
- continue to the ‘What is your National Insurance number?’ question if they do
- ask for their email address
{
'/name': {},
'/do-you-have-a-national-insurance-number': {
'/email': { data: 'have-nino', value: 'No' }
},
'/what-is-your-national-insurance-number': {},
'/email': {}
}
How to get a wizard working
Create a user journey
import { wizard } from 'govuk-prototype-rig'
export function exampleWizard (req) {
const journey = {
'/examples/wizard': {},
'/examples/wizard/name': {},
'/examples/wizard/where-do-you-live': {
// Example fork in the journey:
// Go to nationality page if answer to the question ‘Where do you live?’ is not England
'/examples/wizard/nationality': {
data: 'wizard.where-do-you-live',
excludedValue: 'England'
}
},
'/examples/wizard/england': {},
'/examples/wizard/nationality': {},
'/examples/wizard/check-answers': {},
'/examples/wizard/confirm': {},
'/': {}
}
return wizard(journey, req)
}
Set up the routes
- Make the paths available in the view using routes
- Post each form back to itself, evaluate the paths and redirect to the calculated next page
import { exampleWizard } from './wizards.js'
const router = express.Router()
router.all('/examples/wizard/:view?', (req, res, next) => {
res.locals.paths = exampleWizard(req)
next()
})
router.post('/examples/wizard/:view?', (req, res) => {
res.redirect(res.locals.paths.next)
})
Use a layout which uses the paths object
An example Nunjucks layout extending the default rig layout:
{% extends "layouts/default.html" %}
{% block pageNavigation %}
{{ govukBackLink({
href: paths.back
}) }}
{% endblock %}
{% block content %}
<div class="govuk-grid-row">
<div class="govuk-grid-column-two-thirds">
{% block beforeForm %}{% endblock %}
<form method="post" novalidate>
{% block form %}{% endblock %}
{{ govukButton({
html: buttonText if buttonText else 'Continue'
}) }}
</form>
</div>
</div>
{% endblock %}
Build your question pages
{% extends "layouts/wizard.html" %}
{% set title = "What is your name?" %}
{% block pageNavigation %}
{{ govukBackLink({
href: paths.back
}) }}
{% endblock %}
{% block form %}
{{ govukInput({
label: {
classes: "govuk-label--l",
isPageHeading: true,
text: title
},
decorate: ["wizard", "name"]
}) }}
{% endblock %}