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 %}