Question pages
This pattern explains when to use question pages and what elements they need to include.
New WCAG 2.2 criteria affect this pattern
To use ‘Question pages’ and meet the new Web Content Accessibility Guidelines (WCAG) 2.2 criteria, make sure that users can successfully:
- avoid re-entering information they've given in a previous answer
- select an answer without relying on 'click and drag' movement
See the full list of components and patterns affected by WCAG 2.2.
<div class="govuk-width-container">
<a href="#" class="govuk-back-link">Back</a>
<main class="govuk-main-wrapper " id="main-content" role="main">
<div class="govuk-grid-row">
<div class="govuk-grid-column-two-thirds">
<form action="/form-handler" method="post" novalidate>
<div class="govuk-form-group">
<fieldset class="govuk-fieldset">
<legend class="govuk-fieldset__legend govuk-fieldset__legend--l">
<h1 class="govuk-fieldset__heading">
Where do you live?
</h1>
</legend>
<div class="govuk-radios" data-module="govuk-radios">
<div class="govuk-radios__item">
<input class="govuk-radios__input" id="whereDoYouLive" name="whereDoYouLive" type="radio" value="england">
<label class="govuk-label govuk-radios__label" for="whereDoYouLive">
England
</label>
</div>
<div class="govuk-radios__item">
<input class="govuk-radios__input" id="whereDoYouLive-2" name="whereDoYouLive" type="radio" value="scotland">
<label class="govuk-label govuk-radios__label" for="whereDoYouLive-2">
Scotland
</label>
</div>
<div class="govuk-radios__item">
<input class="govuk-radios__input" id="whereDoYouLive-3" name="whereDoYouLive" type="radio" value="wales">
<label class="govuk-label govuk-radios__label" for="whereDoYouLive-3">
Wales
</label>
</div>
<div class="govuk-radios__item">
<input class="govuk-radios__input" id="whereDoYouLive-4" name="whereDoYouLive" type="radio" value="northern-ireland">
<label class="govuk-label govuk-radios__label" for="whereDoYouLive-4">
Northern Ireland
</label>
</div>
</div>
</fieldset>
</div>
<button type="submit" class="govuk-button" data-module="govuk-button">
Continue
</button>
</form>
</div>
</div>
</main>
</div>
{% from "govuk/components/back-link/macro.njk" import govukBackLink %}
{% from "govuk/components/radios/macro.njk" import govukRadios %}
{% from "govuk/components/button/macro.njk" import govukButton %}
{% block beforeContent %}
{{ govukBackLink({
text: "Back"
}) }}
{% endblock %}
{% block content %}
<div class="govuk-grid-row">
<div class="govuk-grid-column-two-thirds">
<form action="/form-handler" method="post" novalidate>
{{ govukRadios({
name: "whereDoYouLive",
fieldset: {
legend: {
text: "Where do you live?",
isPageHeading: true,
classes: "govuk-fieldset__legend--l"
}
},
items: [
{
value: "england",
text: "England"
},
{
value: "scotland",
text: "Scotland"
},
{
value: "wales",
text: "Wales"
},
{
value: "northern-ireland",
text: "Northern Ireland"
}
]
}) }}
{{ govukButton({
text: "Continue"
}) }}
</form>
</div>
</div>
{% endblock %}
When to use this pattern
Follow this pattern whenever you need to ask users questions within your service.
You should make sure you know why you’re asking every question and only ask users for information you really need.
To help you work out what to ask, you can carry out a question protocol.
If you ask for optional information:
- in most contexts, add ‘(optional)’ to the labels of optional fields
- for radios and checkboxes, add ‘(optional)’ to the legend
Never mark mandatory fields with asterisks.
On every question page you should:
- make sure it’s clear to users why you’re asking each question
- allow users to answer ‘I do not know’ or ‘I’m not sure’ if they are valid responses
Read more about designing good questions in the GOV.UK Service Manual.
How it works
Question pages must include a:
- back link
- page heading
- continue button
If research shows it’s helpful for users, you can also include a progress indicator.
Make sure to only ask for a piece of information once within a single journey. Whenever possible, do not ask a user to re-enter information they’ve already provided. This is to comply with WCAG 2.2 success criterion 3.3.7 Redundant entry.
If the same type of information is needed more than once, make it easier to reuse previously entered answers through one of these methods:
- pre-populating the relevant fields
- showing carried-forward responses as an option for the user to select
Back link
Some users do not trust browser back buttons when they’re entering data.
Always include a back link at the top of question pages to reassure them it’s possible to go back and change previous answers.
However, do not break the browser back button. Make sure it takes users to the previous page they were on, in the state they last saw it.
An exception to this is when the user has performed an action they should only do once, like make a payment or complete an application. The browser back button should still work, but show the user a sensible message rather than let them perform the action again.
Page headings
Page headings can be questions or statements.
Start by asking one question per page
Asking just one question per question page helps users understand what you’re asking them to do, and focus on the specific question and its answer.
To help you follow this approach, you can set the contents of a <legend>
or <label>
for a page’s input as the page heading. This is good practice as it means that users of screen readers will only hear the contents once.
Read more about why and how to set labels and legends as headings or see examples below.
A question page with a legend as the page heading:
<div class="govuk-width-container">
<a href="#" class="govuk-back-link">Back</a>
<main class="govuk-main-wrapper " id="main-content" role="main">
<div class="govuk-grid-row">
<div class="govuk-grid-column-two-thirds">
<form action="/form-handler" method="post" novalidate>
<div class="govuk-form-group">
<fieldset class="govuk-fieldset" role="group" aria-describedby="dob-hint">
<legend class="govuk-fieldset__legend govuk-fieldset__legend--l">
<h1 class="govuk-fieldset__heading">
What is your date of birth?
</h1>
</legend>
<div id="dob-hint" class="govuk-hint">
For example, 31 3 1980
</div>
<div class="govuk-date-input" id="dob">
<div class="govuk-date-input__item">
<div class="govuk-form-group">
<label class="govuk-label govuk-date-input__label" for="dob-day">
Day
</label>
<input class="govuk-input govuk-date-input__input govuk-input--width-2" id="dob-day" name="dob-day" type="text" autocomplete="bday-day" inputmode="numeric">
</div>
</div>
<div class="govuk-date-input__item">
<div class="govuk-form-group">
<label class="govuk-label govuk-date-input__label" for="dob-month">
Month
</label>
<input class="govuk-input govuk-date-input__input govuk-input--width-2" id="dob-month" name="dob-month" type="text" autocomplete="bday-month" inputmode="numeric">
</div>
</div>
<div class="govuk-date-input__item">
<div class="govuk-form-group">
<label class="govuk-label govuk-date-input__label" for="dob-year">
Year
</label>
<input class="govuk-input govuk-date-input__input govuk-input--width-4" id="dob-year" name="dob-year" type="text" autocomplete="bday-year" inputmode="numeric">
</div>
</div>
</div>
</fieldset>
</div>
<button type="submit" class="govuk-button" data-module="govuk-button">
Continue
</button>
</form>
</div>
</div>
</main>
</div>
{% from "govuk/components/back-link/macro.njk" import govukBackLink %}
{% from "govuk/components/date-input/macro.njk" import govukDateInput %}
{% from "govuk/components/button/macro.njk" import govukButton %}
{% block beforeContent %}
{{ govukBackLink({
text: "Back"
}) }}
{% endblock %}
{% block content %}
<div class="govuk-grid-row">
<div class="govuk-grid-column-two-thirds">
<form action="/form-handler" method="post" novalidate>
{{ govukDateInput({
id: "dob",
namePrefix: "dob",
fieldset: {
legend: {
text: "What is your date of birth?",
isPageHeading: true,
classes: "govuk-fieldset__legend--l"
}
},
hint: {
text: "For example, 31 3 1980"
},
items: [
{
name: "day",
classes: "govuk-input--width-2",
autocomplete: "bday-day"
},
{
name: "month",
classes: "govuk-input--width-2",
autocomplete: "bday-month"
},
{
name: "year",
classes: "govuk-input--width-4",
autocomplete: "bday-year"
}
]
}) }}
{{ govukButton({
text: "Continue"
}) }}
</form>
</div>
</div>
{% endblock %}
A question page with a label as the page heading:
<div class="govuk-width-container">
<a href="#" class="govuk-back-link">Back</a>
<main class="govuk-main-wrapper " id="main-content" role="main">
<div class="govuk-grid-row">
<div class="govuk-grid-column-two-thirds">
<form action="/form-handler" method="post" novalidate>
<div class="govuk-form-group">
<h1 class="govuk-label-wrapper">
<label class="govuk-label govuk-label--l" for="postcode">
What is your home postcode?
</label>
</h1>
<input class="govuk-input govuk-input--width-10" id="postcode" name="postcode" type="text" autocomplete="postal-code">
</div>
<button type="submit" class="govuk-button" data-module="govuk-button">
Continue
</button>
</form>
</div>
</div>
</main>
</div>
{% from "govuk/components/back-link/macro.njk" import govukBackLink %}
{% from "govuk/components/input/macro.njk" import govukInput %}
{% from "govuk/components/button/macro.njk" import govukButton %}
{% block beforeContent %}
{{ govukBackLink({
text: "Back"
}) }}
{% endblock %}
{% block content %}
<div class="govuk-grid-row">
<div class="govuk-grid-column-two-thirds">
<form action="/form-handler" method="post" novalidate>
{{ govukInput({
label: {
text: "What is your home postcode?",
isPageHeading: true,
classes: "govuk-label--l"
},
classes: "govuk-input--width-10",
id: "postcode",
name: "postcode",
autocomplete: "postal-code"
}) }}
{{ govukButton({
text: "Continue"
}) }}
</form>
</div>
</div>
{% endblock %}
Do not use the same page heading across multiple pages.
The page heading should relate specifically to the information being asked for on the current page, not any higher-level section the page is part of.
If you need to show the high-level section, you can use the govuk-caption
style.
For example, ‘About you’
<span class="govuk-caption-l">About you</span>
<h1 class="govuk-heading-l">
What is your home address?
</h1>
You can also learn more about how starting with one thing per page helps users in the GOV.UK Service Manual.
Asking complex questions without using hint text
Do not use hint text if you need to give a lengthy explanation with lists and paragraphs. Screen readers read out the entire text when users interact with the form element. This could frustrate users if the text is long.
Do not use links in hint text. While screen readers will read out the link text when describing the field, they will not tell users the text is a link.
If you’re asking a question that needs a detailed explanation, use:
- a
h1
heading that’s a statement (for example, ‘Interview needs’) rather than a question - whatever mix of text, paragraphs, lists and examples best explains your question to users
- a label, above the form input, that asks users a specific question – for example, ‘Do you have any interview needs?’
<div class="govuk-width-container">
<a href="#" class="govuk-back-link">Back</a>
<main class="govuk-main-wrapper " id="main-content" role="main">
<div class="govuk-grid-row">
<div class="govuk-grid-column-two-thirds">
<h1 class="govuk-heading-l">
Interview needs
</h1>
<p class="govuk-body">
Providers do not usually have much flexibility when setting a date and time for interview unless you need adjustments due to a <a href="#" class="govuk-link">health condition or disability</a>.
</p>
<p class="govuk-body">
However, if you need flexibility for other reasons you can tell us about it here.
</p>
<p class="govuk-body">
For example, you have commitments like caring responsibilites or employment.
</p>
<p class="govuk-body">
Contact your provider if you’re concerned about the interview process.
</p>
<form action="/form-handler" method="post" novalidate>
<div class="govuk-form-group">
<fieldset class="govuk-fieldset">
<legend class="govuk-fieldset__legend govuk-fieldset__legend--m">
Do you have any interview needs?
</legend>
<div class="govuk-radios" data-module="govuk-radios">
<div class="govuk-radios__item">
<input class="govuk-radios__input" id="interviewNeeds" name="interviewNeeds" type="radio" value="yes">
<label class="govuk-label govuk-radios__label" for="interviewNeeds">
Yes
</label>
</div>
<div class="govuk-radios__item">
<input class="govuk-radios__input" id="interviewNeeds-2" name="interviewNeeds" type="radio" value="no">
<label class="govuk-label govuk-radios__label" for="interviewNeeds-2">
No
</label>
</div>
</div>
</fieldset>
</div>
<button type="submit" class="govuk-button" data-module="govuk-button">
Continue
</button>
</form>
</div>
</div>
</main>
</div>
{% from "govuk/components/back-link/macro.njk" import govukBackLink %}
{% from "govuk/components/radios/macro.njk" import govukRadios %}
{% from "govuk/components/button/macro.njk" import govukButton %}
{% block beforeContent %}
{{ govukBackLink({
text: "Back"
}) }}
{% endblock %}
{% block content %}
<div class="govuk-grid-row">
<div class="govuk-grid-column-two-thirds">
<h1 class="govuk-heading-l">
Interview needs
</h1>
<p class="govuk-body">
Providers do not usually have much flexibility when setting a date and time for interview unless you need adjustments due to a <a href="#" class="govuk-link">health condition or disability</a>.
</p>
<p class="govuk-body">
However, if you need flexibility for other reasons you can tell us about it here.
</p>
<p class="govuk-body">
For example, you have commitments like caring responsibilites or employment.
</p>
<p class="govuk-body">
Contact your provider if you’re concerned about the interview process.
</p>
<form action="/form-handler" method="post" novalidate>
{{ govukRadios({
name: "interviewNeeds",
fieldset: {
legend: {
text: "Do you have any interview needs?",
isPageHeading: false,
classes: "govuk-fieldset__legend--m"
}
},
items: [
{
value: "yes",
text: "Yes"
},
{
value: "no",
text: "No"
}
]
}) }}
{{ govukButton({
text: "Continue"
}) }}
</form>
</div>
</div>
{% endblock %}
Asking multiple questions on a page
Sometimes it makes sense to group a number of related questions on the same page.
User research will tell you when you can group pages together. For example, if you’re designing an internal service for government users who need to repeat and switch between tasks quickly.
If you need to ask for multiple related things on a page, use a statement as the heading.
You can style each <label>
or <legend>
to make the questions easier to scan. Read more about why and how to style labels and legends.
<div class="govuk-width-container">
<a href="#" class="govuk-back-link">Back</a>
<main class="govuk-main-wrapper " id="main-content" role="main">
<div class="govuk-grid-row">
<div class="govuk-grid-column-two-thirds">
<h1 class="govuk-heading-l">Passport details</h1>
<form action="/form-handler" method="post" novalidate>
<div class="govuk-form-group">
<label class="govuk-label govuk-label--m" for="passport-number">
Passport number
</label>
<div id="passport-number-hint" class="govuk-hint">
For example, 502135326
</div>
<input class="govuk-input govuk-input--width-10" id="passport-number" name="passportNumber" type="text" aria-describedby="passport-number-hint">
</div>
<div class="govuk-form-group">
<fieldset class="govuk-fieldset" role="group" aria-describedby="expiry-hint">
<legend class="govuk-fieldset__legend govuk-fieldset__legend--m">
Expiry date
</legend>
<div id="expiry-hint" class="govuk-hint">
For example, 31 3 1980
</div>
<div class="govuk-date-input" id="expiry">
<div class="govuk-date-input__item">
<div class="govuk-form-group">
<label class="govuk-label govuk-date-input__label" for="expiry-day">
Day
</label>
<input class="govuk-input govuk-date-input__input govuk-input--width-2" id="expiry-day" name="expiry-day" type="text" inputmode="numeric">
</div>
</div>
<div class="govuk-date-input__item">
<div class="govuk-form-group">
<label class="govuk-label govuk-date-input__label" for="expiry-month">
Month
</label>
<input class="govuk-input govuk-date-input__input govuk-input--width-2" id="expiry-month" name="expiry-month" type="text" inputmode="numeric">
</div>
</div>
<div class="govuk-date-input__item">
<div class="govuk-form-group">
<label class="govuk-label govuk-date-input__label" for="expiry-year">
Year
</label>
<input class="govuk-input govuk-date-input__input govuk-input--width-4" id="expiry-year" name="expiry-year" type="text" inputmode="numeric">
</div>
</div>
</div>
</fieldset>
</div>
<button type="submit" class="govuk-button" data-module="govuk-button">
Continue
</button>
</form>
</div>
</div>
</main>
</div>
{% from "govuk/components/back-link/macro.njk" import govukBackLink %}
{% from "govuk/components/input/macro.njk" import govukInput %}
{% from "govuk/components/date-input/macro.njk" import govukDateInput %}
{% from "govuk/components/button/macro.njk" import govukButton %}
{% block beforeContent %}
{{ govukBackLink({
text: "Back"
}) }}
{% endblock %}
{% block content %}
<div class="govuk-grid-row">
<div class="govuk-grid-column-two-thirds">
<h1 class="govuk-heading-l">Passport details</h1>
<form action="/form-handler" method="post" novalidate>
{{ govukInput({
label: {
text: "Passport number",
classes: "govuk-label--m"
},
hint: {
text: "For example, 502135326"
},
classes: "govuk-input--width-10",
id: "passport-number",
name: "passportNumber"
}) }}
{{ govukDateInput({
id: "expiry",
namePrefix: "expiry",
fieldset: {
legend: {
text: "Expiry date",
classes: "govuk-fieldset__legend--m"
}
},
hint: {
text: "For example, 31 3 1980"
}
}) }}
{{ govukButton({
text: "Continue"
}) }}
</form>
</div>
</div>
{% endblock %}
Continue button
Make sure your ‘Continue’ button is:
- labelled ‘Continue’, not ‘Next’
- aligned to the left so users do not miss it
Using progress indicators
Start by testing your form without a progress indicator to see if it’s simple enough that users do not need one.
Try improving the order, type or number of questions before adding a progress indicator. If people still have difficulty, try adding a simple step or question indicator like this one.
<span class="govuk-caption-l">Question 3 of 9</span>
<h1 class="govuk-heading-l">
Your details
</h1>
<span class="govuk-caption-l">Question 3 of 9</span>
<h1 class="govuk-heading-l">
Your details
</h1>
Only include the total number of questions if you can do so reliably. As the user moves through the form, make sure the indicator updates to tell them which question they are on and the total number remaining.
Do not use progress indicators that do all of the following:
- show all questions at once
- allow navigation to previous questions
- show the current question
An example of this looks like:
These can be problematic because they:
- are often not noticed
- take up lots of space
- do not scale well on small screens
- can distract and confuse some users
- make it hard to write good labels for the steps
- make it hard to handle conditional sections
A number of GOV.UK services have removed this style of progress indicator without any negative effects. Read a blog post about how the Carer’s Allowance team removed a 12-step progress indicator with no effect on completion rates or times.
Using range sliders
Avoid using range slider questions, where the user needs to click and drag a selector across a range of answers or values. These types of controls are difficult for some users to interact with.
If you do use a range slider, you must provide a method for selecting an answer that doesn’t rely on ‘click and drag’ movements. This relates to WCAG success criterion 2.5.1 Pointer Gestures.
Help improve this pattern
To help make sure that this page is useful, relevant and up to date, you can:
- take part in the ‘Question pages’ discussion on GitHub and share your research
- propose a change – read more about how to propose changes in GitHub
Tell us if your service uses this pattern
Take part in our usage survey (opens in a new tab) to help us improve this pattern to better meet the needs of the services that use it.
Need help?
If you’ve got a question about the GOV.UK Design System, contact the team.