Forms
The examples on this page show how we manage forms and their fields, and their default styles. Recommendations draw from Adam Silver's article Form design: from zero to hero all in one blog post and the GOV.UK design system.
An example search form is available in core components.
Form error messages are covered separately.
Top tips
- Every input needs a label.
- Do not wrap inputs in labels: put the
labelbefore theinput(except for radio buttons and checkboxes, where theinputshould come first) - Provide a unique ID for the
input - Use the
forattribute on thelabelto reference the input's ID - Wrap each label/input pair in a plain
div.
- Do not wrap inputs in labels: put the
- Form fields must look like form fields: use a visible border and make sure that fields are empty to begin with.
- Placeholders are problematic. Avoid using the
placeholderattribute, especially for providing any meaningful instructions. Do not use it instead of a visiblelabel. - Use fixed width inputs for content with a specific, known length. Post code inputs should be wide enough for a post code, telephone number inputs should be wide enough to hold a telephone number.
- Select dropdowns should be a last resort as they’re really hard to use. Try radio buttons instead. If there’s a long list of options, use JavaScript to enhance the
selectinto an accessible auto-complete field (not to be confused with theautocompleteattribute). - If you have to use a
selectand selecting an option will result in a change of context (e.g. a page reload/refresh causing a change in focus), that change must be triggered by an accompanying confirmatory button, not by the change to theselectvalue.- Note that
selectworks very differently outside the MacOS environment: using the arrow keys in Windows automatically switches between options, while on MacOS it first brings up the list of options.
- Note that
- Make sure any
buttonlooks like a button. Align them with the left edge of the last input (the right edge for right-to-left languages) where users naturally look for them. Use a verb for button text because the user is doing something, and relate it to what they are doing - avoid generic ‘Submit’ buttons.
Required fields
- Add “(required)” to the end of the visible text in the
label- Groups of radio buttons or checkboxes should be contained in a
fieldsetwith alegend. Add “(required)” to the end of the visible text in thelegend
- Groups of radio buttons or checkboxes should be contained in a
- Add the
requiredattribute to the form input- Radio buttons: at least one of the inputs in a group of same-named radio buttons must have the
requiredattribute - Checkbox group: in the event that at least one checkbox in a group must be checked, there is currently no way to apply this attribute to indicate this. Note the requirement in the
legendtext.
- Radio buttons: at least one of the inputs in a group of same-named radio buttons must have the
Adding hint text
Provide hint text when users are more likely to make a mistake, such as when having to satisfy a complex set of password rules. Error messages should be a last resort. Keep it brief and to the point. Do not use long paragraphs and lists.
- Use
<div class="field-hint">to provide the hint text. Check the examples that follow to see where to add it (this is slightly different for checkbox and radio inputs). - Each instance of
<div class="field-hint">must have a unique ID. It is suggested to use the patternid="hint-..., replacing the...with some unique wording that relates to the input purpose. - Add the
aria-describedbyattribute to theinputorfieldsetwhich the hint text applies to, populating it with the ID of the relevant field hint.
Dealing with text
How to make filling in text fields easier
Use the relevant input type when asking for email addresses, URLs and passwords.
Adding the autocomplete attribute to common fields such as name, address, email etc. can help to speed up the form filling process for users. Find valid autocomplete values on the MDN site.
Use autocapitalize="none", autocorrect="off" and spellcheck="false" to stop browsers automatically changing user input on fields that expect grammatically incorrect data, such as email addresses and passwords.
Dealing with numbers
How to make filling in number fields easier
In many cases, it's better to use input type="text" pattern="[0-9]*" inputmode="numeric" rather than input type="number" when dealing with numbers. Adam Silver has written about when to use the number input.
For telephone numbers, use the type="tel" and inputmode="tel" attributes on the input.
When asking for payment details, including the autocomplete attribute can help users complete their responses more quickly. Older browsers make use of the name attribute to achieve the same thing. Here is a list of payment autofill attributes.
Dealing with dates and times
How to make providing dates and times easier
For dates that the user will already know (e.g. birth dates) and dates that are easy to look up, use a series of simple text inputs. Note the use of fieldset and legend to group the separate text inputs together.
For other dates, due to inconsistencies with how different browsers and Assistive Technologies interpret input type="date", the current recommendation is to use a simple text input. Provide hint text to let users know what format to use.
Again, due to inconsistencies with how different browsers and Assistive Technologies interpret input type="time", it is strongly recommended to use a simple text input. The preceding example includes a select to help users specify a local timezone.
File input
Checkboxes
How to make checkboxes easier to use
Always position checkboxes to the left of their labels (to the right for right-to-left languages). This makes them easier to find, especially for users of screen magnifiers.
If required, hint text can be added for the entire checkbox group and/or for individual checkbox items. The preceding example shows how to do this.
Radios
How to make radios easier to use
Always position radios to the left of their labels (to the right for right-to-left languages). This makes them easier to find, especially for users of screen magnifiers.
Radio buttons cannot be unchecked once they are selected. So if the question is not mandatory, you'll need to include a ‘None’ or ‘Prefer not to say’ option.
If required, hint text can be added for the entire radio group and/or for individual radio items. The preceding example shows how to do this.
Segmented options
The purpose of segmented options is to show all available options outright, rather than hiding them behind a select. It can be used with checkboxes, or with radio buttons as in the preceding example (even though it's using a tick).
The basis of this pattern is the switcher layout.
Select
Considerations
The select element should be a last resort as they’re really hard to use. Before using it, try asking users questions which will allow you to present them with fewer options. This should lessen the need for the select element, which could be replaced with e.g. radios.
If using the select element to determine a change in browsing context (e.g. change to a map display or redirect to a different URL) it must be accompanied by a submit button, so that users can confirm their choice and make a correction if needed.
Accessible auto-complete
A select can be enhanced into an accessible auto-complete via JavaScript. Amplify uses the Accessible autocomplete NPM package, and there are a number of example customisations which can be followed.
Grouping inputs to line up side-by-side
The class input-group can be used to align form inputs horizontally with each other, by applying Flexbox behaviour. You can see an example of this in the preceding example for dealing with times.
Considerations
This class should not be used in conjunction with radios or checkboxes. The pattern has not been fully tested with these input types and may not work well on smaller viewports. Furthermore, radios and checkboxes are easier to read and quicker to scan when presented vertically.
Fixed-width inputs
There is a collection of CSS classes prefixed with input-width- which, when added to an input, will reduce the maximum width of the input field to better suit the intended contents:
Form validation
The best practice is to validate a form on submission. It is recommended to avoid default HTML5 form validation. To turn this off, add the novalidate attribute to the form element.
It is strongly recommended to visit the GOV.UK Design system for more details about form validation.
Client side validation
If client side validation is required, here are some suggested JavaScript libraries:
Alternatively, you could roll your own thanks to Chris Ferdinandi's series on form validation.