Form patterns
Forms are where content design and accessibility overlap the most. Every label, hint, and validation message is a piece of content that either helps someone complete their task or gets in their way.
Good form content reduces errors, builds trust, and respects people's time.
Labels
Every form input needs a visible label. No exceptions. This is a WCAG requirement (SC 1.3.1, 3.3.2) and a usability fundamental.
| Do | Don't |
|---|---|
| Email address | Enter your email address here: |
| Full name | Your Name |
| Date of birth | DOB |
| Phone number | Tel. |
Label rules
- Sentence case. "Email address" not "Email Address"
- No colons at the end
- No full stops. Labels aren't sentences
- Be specific. "Work email" is better than "Email" when you need both personal and work
- Don't use abbreviations. "Date of birth" not "DOB." Write it out.
- Don't turn labels into questions. "Company" not "What company do you work for?"
- Keep them short. 1 to 3 words is ideal. If you need more, the field might need redesigning.
For more on labels and other UI text, see microcopy.
Required and optional fields
Mark the minority. This keeps the form clean and reduces visual clutter.
| Situation | Pattern | Example |
|---|---|---|
| Most fields are required | Mark the optional ones | Phone number (optional) |
| Most fields are optional | Mark the required ones | Email address (required) |
Rules
- Don't use asterisks alone. If you use an asterisk (_), you must also include a text explanation at the top of the form: "Fields marked with _ are required." But plain text (such as "(required)" or "(optional)") is clearer and more accessible.
- Put the marker after the label. "Phone number (optional)" not "(optional) Phone number"
- Don't mark every field. If all fields are required, say so once at the top: "All fields are required." Don't mark each one individually.
- Use lowercase. "(optional)" not "(Optional)"
Help text
Help text appears below a form field to provide context, format hints, or constraints. It stays visible while the user interacts with the field.
| Do | Don't |
|---|---|
| Must be at least 8 characters | Your password should be at least 8 characters long and contain at least 1 uppercase letter, 1 lowercase letter, 1 number, and 1 special character |
| We'll send a verification link to this address | Please enter a valid and current email address that you have access to |
| Format: DD/MM/YYYY | Enter the date using the day/month/year format as shown |
Help text rules
- Put it below the input, not above. The reading order is: label, input, help text.
- Keep it to 1 short sentence. If you need a paragraph, the form design needs rethinking
- Don't repeat the label. Help text should add new information
- Use
aria-describedbyto associate help text with the input. This ensures screen readers announce the help text when the user focuses on the field. - Only add help text where it's needed. If the label is clear enough on its own, skip it
Validation messages
Validation tells people what went wrong and how to fix it. It should be immediate, specific, and helpful.
Inline validation
Show the validation message directly below the field, in the same position as help text. Use colour and an icon together to distinguish errors from help text. Colour alone isn't enough (WCAG SC 1.4.1).
| Do | Don't |
|---|---|
| Enter a valid email address, like name@example.com | Invalid input |
| Select a country from the list | This field is required |
| Enter a date after today | Invalid date |
| Passwords must match | Error |
| Enter a number between 1 and 100 | Out of range |
Validation summary
For forms with multiple errors, show a summary at the top of the form after submission. The summary should:
- List each error with a link to the relevant field
- Describe the error specifically (not just "This field has an error")
- Move focus to the summary so screen readers announce it immediately
When to validate
| Approach | When to use |
|---|---|
| On submit | Default approach. Validate everything when the form is submitted. Less intrusive. |
| On blur (leaving a field) | Use for fields where immediate feedback is helpful: email format, password strength, username availability. |
| On input (as the user types) | Use sparingly. Only for real-time feedback like character counts or password strength indicators. Don't show errors while someone is still typing. |
Validation message rules
- Be specific about what's wrong. "Enter a date in DD/MM/YYYY format" not "Invalid format"
- Tell them how to fix it. "Choose a password with at least 8 characters" not "Password too short"
- Don't blame the user. "Enter an email address" not "You forgot to enter your email"
- Use the same position as help text. Below the field, associated with
aria-describedby - Don't clear the field when showing an error. Let people see what they typed and correct it
Input formatting
How to handle dates, numbers, and other formatted inputs.
Dates
Follow the tone of voice writing rule: day, month, year.
| Format | When to use | Example |
|---|---|---|
| Written out | Display, content, emails | 25 February 2026 |
| DD/MM/YYYY | Form inputs with a single field | 25/02/2026 |
| Separate fields | Complex forms, date of birth | Day: 25, Month: February, Year: 2026 |
- Never use American date format (MM/DD/YYYY)
- Don't use slashes in display text. Write the month name out
- If using a date picker, also allow manual entry. Not everyone can use a date picker
- Show the expected format as help text. "Format: DD/MM/YYYY"
Times
Lowercase, no space between number and am/pm.
| Do | Don't |
|---|---|
| 3pm | 3:00 PM |
| 9.30am | 9:30 AM |
| 12 noon | 12:00 PM |
Phone numbers
Let people enter phone numbers in whatever format they're comfortable with. Format the display on blur or on save.
| Do | Don't |
|---|---|
| Accept: 07700900000, +447700900000, 07700 900 000 | Force a specific format during entry |
| Display: +44 7700 900 000 | Show the raw input with no formatting |
Currency
Symbol before the number. 2 decimal places for most currencies. Use commas for thousands.
| Do | Don't |
|---|---|
| $1,234.56 | 1234.56 USD |
| 950.00 | 950 |
Grouping and fieldsets
Group related fields using <fieldset> and <legend>. The legend provides context for the group.
When to use fieldsets
| Use fieldset for | Don't use fieldset for |
|---|---|
| Radio button groups | Every section of a form |
| Checkbox groups | Single inputs |
| Related field sets (address, payment details) | Visual grouping only (use headings instead) |
| Groups where the label only makes sense in context | Fields that each have clear, standalone labels |
Example: A group of radio buttons labelled "Red," "Blue," and "Green" needs a fieldset with the legend "Favourite colour." Without it, screen readers just hear "Red" with no context.
Accessibility checklist for forms
Before shipping a form, check it against these requirements:
- All inputs have visible, associated
<label>elements (SC 1.3.1, 3.3.2) - Required fields are identified in text, not just by colour or asterisk alone (SC 3.3.2)
- Error messages identify the field and describe the error in text (SC 3.3.1)
- Error suggestions are provided where the system can detect the correct format (SC 3.3.3)
- Help text is associated with inputs using
aria-describedby - Related inputs are grouped with
<fieldset>and<legend> - The form can be completed using keyboard only
- Focus moves to the error summary or first error field on submission failure
- Error states use colour plus icon or text (not colour alone)
- Date inputs accept keyboard entry, not just date picker
For the full accessibility specification, see accessibility standards.