FormsWarning: Draft
We recommend using our Form control component to automatically handle accessibility for form controls. The guidelines on this page have been used to inform the implementation of our Telescope form components and should only be necessary to use outside of Telescope when creating custom form components.
Naming
To satisfy WCAG 4.2.1 ("For all user interface components, the name and role can be programmatically determined"), an input must be named.
An accessible name is a short string of text that’s programatically associated with a UI element. Its purpose is to help assistive technology users understand the UI element’s purpose and distinguish it from other UI elements on the page.
This is unrelated to the name
attribute in HTML.
Providing an accessible name
Use a <label>
element and give its for
attribute a value matching the form control’s id
.
Avoid nesting form controls within a <label>
. This works in theory, but assistive technology support for this pattern is inadequate.
<label for="expense-category">Expense category</label> <input type="text" id="”expense-category" />
Using aria-labelledby
Use aria-labelledby
when the form control’s label is present in the markup but can't be changed to a <label>
element, such as when it needs to be a <div>
or <span>
. Give the form control’s aria-labelledby
attribute a value matching the label’s id
attribute.
<span id="expense-category">Expense category</span><input type="text" aria-labelledby="expense-category" />
Using aria-label
In general, avoid using aria-label
to give form controls an accessible name.
Use aria-label
when the form control’s label is not in the markup and you can’t add it to the markup. Or when the label is in the markup, but you can’t change it to a <label>
element or use aria-labelledby
to associate it with the form control.
In the latter case, make sure the visible label matches the value of the aria-label
. Note, in addition to other issues with using aria-label, this means that screen reader users may hear the same label twice.
<span>Expense category</span> <input type="text" aria-label="Expense category" />
Hiding a label visually
Without a visible label, it can be difficult for people to understand or remember what they should fill in or select. This especially impacts people with cognitive impairments.
It’s only acceptable to hide a visible label when a common design pattern is used in a context with visual cues that clarify the form control’s purpose. An example is a search field placed near the top of a page, featuring a magnifying glass icon and/or a button labelled “Search”.
Note, form controls without visible labels still need accessible names. We recommend using our VisuallyHidden component for this use case. Wrap it around a <label>
with a for
attribute matching the form control’s id
.
<VisuallyHidden><label for="search-field">Search</label></VisuallyHidden><input type="search" id="search-field" />
Names for multiple related form controls
Related form controls are form controls that share a theme or purpose. For example, a set of radio buttons to select the payment status of an expense. Or a group of text fields used to input an address (e.g., street, apartment number, city, zip code).
To provide an accessible name to related form controls, start by wrapping them in a <fieldset>
element. Then, use the aria-labelledby
attribute on the <fieldset>
to reference the id
of the text element that serves as the visible label.
<span id="payment-status">Payment status</span><fieldset aria-labelledby="payment-status"><input type="checkbox" id="pending" /><label for="pending">Pending</label><input type="checkbox" id="settled" /><label for="settled">Settled</label><input type="checkbox" id="Refund" /><label for="Refund">Refund</label></fieldset>
Descriptions
An accessible description is a text string that provides extra context about a UI element, helping assistive technology users to understand its purpose or requirements. Typically longer than an accessible name, it can include instructions or clarifications.
To provide a form control with an accessible description, use the aria-labelledby
attribute on the <input>
element (or <fieldset>
for groups of related form controls) to reference the id
of the text element containing the description.
<label for="password">Create a password</label><input type="password" id="password" aria-describedby="password-requirements" /><p id="password-requirements">Your password must be at least 8 characters long and include a mix of letters, numbers, andspecial symbols.</p>
Required form controls
To inform assistive technology users that a single form control is required, add aria-required=”true”
to the form control.
<label for="name">Your name</label> <input type="text" id="name" aria-required="true" />
Avoid using required
instead of aria-required=”true”
, as some browser and screen reader pairings announce the form control as invalid before the user has started typing.
For a group of related form controls, mention it’s required in its accessible name.
<span id="expense-category">Expense category (select at least one)</span><fieldset aria-labelledby="expense-category"><input type="checkbox" id="software" /><label for="software">Software</label><input type="checkbox" id="travel" /><label for="travel">Travel</label><input type="checkbox" id="training" /><label for="training">Training</label></fieldset>
Avoid adding aria-required=”true”
to a <fieldset>
element. It only works with some browser and screen reader pairings. More importantly, it’s invalid, as aria-required
should only be used on interactive elements and the <fieldset>
element maps to the group
role, which represent non-interactive document structure elements.
Invalid form controls
When a form control becomes invalid, assistive technology users need clear, accessible feedback to resolve the error.
Marking a form control as invalid
- Add the
aria-invalid
attribute to the form control and set its value to“true”
- Add an error message after the form control and its optional description
- Add an
aria-describedby
attribute to the form control and anid
to the error message. Ifaria-describedby
is already being used, prepend theid
of the error message, so the user first hears what's wrong and then hears the instructions from the hint text. - Match the values of the
aria-describedby
andid
attributes - When the form control is no longer invalid, remove the
aria-invalid
attribute completely instead of setting it to“false”
<label for="password">Create a password</label><inputid="password"aria-describedby="error password-requirements"aria-required="true"aria-invalid="true"/><p id="password-requirements">Your password must be at least 8 characters long and include a mix of letters, numbers, andspecial symbols.</p><p id="error">The password you entered is too short.</p>
Avoid using aria-errormessage
, due to inconsistent support across browsers and screen readers (source 1, source 2), despite its semantic appropriateness.
Handling form submission errors
If a user has tried to submit a form with a single invalid form control, mark it as invalid and provide it with an error message. Additionally, move the user’s focus to the invalid form control.
If multiple form controls are invalid, display an error summary at the top of the form. It should satisfy the following criteria:
- Each error links to its corresponding invalid form control
- The errors are worded the same as those next to the invalid form controls
- The error summary has a descriptive heading
- The user’s focus is moved to the error summary’s heading. (As the heading is not interactive, it’s not inherently focusable. To make it focusable without adding it to the natural tabbing order of the page, set its
tabindex
attribute to-1
.) - Every invalid form control is marked as invalid and provided with an error message
<div><h2 tabindex="-1">Please correct the following 3 errors</h2><ul><li><a href="#full-name">Enter your full name</a></li><li><a href="#email">Enter your email address</a></li><li><a href="#address">Enter your address</a></li></ul></div>
Linking to invalid form controls is recommended by the W3C as an advisory technique to comply with WCAG Success Criteria 3.3.1 Error Identification (Level A) and 3.3.3 Error Suggestion (Level AA).
Implementing live validation
As our Forms guidelines state, only use live validation for longer forms and strict input fields. Also, validate on blur instead of during interaction with the form control.
Before the form control becomes invalid, make sure a container is present in the markup with role=”status”
. The “status”
role ensures that when content, such as an error message, gets added to the container, screen readers will announce it
<label for="password">Create a password</label><input id="password" aria-describedby="password-requirements" aria-required="true" /><p id="password-requirements">Your password must be at least 8 characters long and include a mix of letters, numbers, andspecial symbols.</p><div role="status"></div>
When the form control becomes invalid, add an error message to the role=”status”
container. Also, follow the guidelines about marking the form control as invalid.
<label for="password">Create a password</label><inputid="password"aria-describedby="error password-requirements"aria-required="true"aria-invalid="true"/><p id="password-requirements">Your password must be at least 8 characters long and include a mix of letters, numbers, andspecial symbols.</p><div role="status"><p id="error">The password you entered is too short.</p></div>