Accessible web forms

Let’s take a dive into using forms in our web applications.

Anatomy of an HTML form

Input purpose

Step 1 to making form input purpose clear is to use adequate instruction and labelling. The success criterion 3.3.2 for Level A compliance regarding labels:

Labels or instructions are provided when content requires user input.

Form control labels are mandatory. They give people context around the data they are submitting. In the case where having a label is unnecessary for sighted users, we should include a label even if it’s not rendered in the UI.

An additional benefit of using labels is that users can click on labels to focus the associated form control!

<label for=”username”>Click me</label>
<input id=”username” type=”text”>

Assistive technologies are able to identify labels and present the label text to the user in a familiar manner. Screen reader users generally navigate through a form using the Tab key to jump from form control to form control. Associated form labels are read for each form control when the user navigates to them. Any non-label text content between the form controls is usually skipped over. Be sure to include important cues or instructions in associated labels or at the beginning of the form.

In some situations, form controls cannot be labeled explicitly. For example, a content author might not know the ID of a form field generated by a script, or a script might not add an ID to a dynamically created element. In this case, the label element can be used as a container for both the form control and the label text so that the two are associated implicitly.

First name:
<input type="text" name="firstname">

Generally, explicit labels are better supported by assistive technology.

One of the following three techniques should be used when a visible label is not an option:

  • Hide the label element with CSS.
  • Use a title attribute. If a form field has a title attribute, but no label, the screen reader will read the title as if it were a label. This technique will also cause a tooltip to appear when the user hovers over the field with a mouse, which could be distracting for some users.
  • Use an aria-label. Unlike aria-labelledby which must reference another element, aria-label contains the label text directly. As with aria-labelledby, aria-label will override any associated label elements.

Only one of these recommendations should be implemented. Using two or more together (e.g., a hidden label and a duplicate title attribute) can cause information to be repeated by a screen reader. Also note that placeholder text (e.g., <input type="text" placeholder="Search this site">) is not a suitable label and should never be used in place of the above techniques.

In addition to the situations where a visible label element is not an option, there are other times when the label element falls short. It cannot be used to provide multiple labels for a single form control or to associate a single label with multiple form controls. The majority of these labeling limitations can be overcome with three ARIA properties (aria-labelledby, aria-describedby, and aria-label).


The aria-labelledby attribute solves the problem of not being able to establish a 1-to-many or many-to-1 relationship between input and label elements. The value of aria-labelledby should be one or more element IDs of the label element(s). If a control has both an associated label and aria-labelledby, the referenced aria-labelledby text will override and be read instead of the associated label.

<h3 id=”label”>Women’s Outerwear</h3>
<button id=”button” aria-labelledby=”label button”>
Shop now

As a general rule, if a single label is present for a single control, the label element should be used to reference it. These labels provide additional functionality - clicking on them sets focus to or activates the control. This functionality is not available when using aria-labelledby.


The aria-describedby attribute is great for when a form includes information that isn't exactly a label but is important enough to be read by a screen reader when navigating to the form control.

While the aria-labelledby attribute overrides the label, aria-describedby does not. This means that aria-describedby should only be used in addition to a label, not instead of one.

The aria-describedby attribute can also be used to reference descriptions that appear as 'tooltips'. As a side note, tooltips should become visible to sighted keyboard users when the control has keyboard focus, not just when the user hovers or clicks with a mouse.

Outside of labels, how can we ensure the purpose of our input controls is effectively conveyed?

The success criterion 1.3.5 for Level AA compliance regarding input purpose:

The purpose of each input field collecting information about the user can be programmatically determined when:

Translation: every user should be able to discern the purpose of a form input. If we make the input purpose clear to the user agent, it allows folks accessing the user agent via different modalities to understand what’s needed to correctly input the data.

It’s important to note the difference between intent and purpose. If you have an address input the user may be able to discern that the intent is for them to enter an address but what will the address data be used for? Is this a shipping address? Billing address?

So how do we satisfy this requirement? As an example, say we have an input to capture a user’s name. The autocomplete attribute can be used to add another layer of specificity to the input purpose. Attribute values like “name”, “given-name”, “family-name”, “username” and “nickname” all make clear the reason for the data input.

A secondary benefit of using an autocomplete attribute to fulfill this success criterion is that it allows for input suggestions based on the user’s past form submissions. This can be especially beneficial for users who live with language and memory related disabilities or disabilities that affect executive function and decision-making.

Additionally, when input purpose is clearly defined, assistive technology can add icons to input fields to communicate the purpose of the fields visually to help people with cerebral palsy, stroke, head injury, motor neuron disease or learning disability who sometimes prefer images for communication.

How else can we ensure that the purpose of an input is programmatically understood? According to supporting documentation for success criterion 1.3.5:

When the user agent and assistive technology support for other metadata formats matures, metadata schemes like the Personalization Semantics Content Module may be used in addition or instead of the HTML autocomplete attribute to identify the purpose of input fields.

At the time of writing, it looks like the Personalization Semantics Content Module is still a draft.

Form controls

WebAIM offers a list of form control examples which are nice to test with a screen reader for comparison purposes. This list includes text inputs, textareas, checkboxes, radio buttons, select menus, buttons, image buttons, and JavaScript jump menus.

The aria-required attribute can be used to identify required fields to screen reader users, especially if the label text does not indicate this or if color-alone or an asterisk are used to identify the required fields.

HTML5 now has the required attribute, but aria-required is still useful for user agents that do not yet support HTML5.

Source MDN article

Groupings of form controls, typically groups of related checkboxes and radio buttons, sometimes require a higher level description (such as "Shipping Method" for a group of shipping option radio buttons). This descriptive text can be associated to the group of form controls using fieldset and legend. The fieldset identifies the entire grouping and legend identifies the grouping's descriptive text. Using fieldset and legend ensures that the text description is read to screen reader users when the grouping is navigated to.

In addition to grouping our controls appropriately, we should be using intuitive controls in our forms. For example, it is recommended that multiple select menus be avoided. Not all browsers provide intuitive keyboard navigation for multiple select menus. Many users do not know to use CTRL/Command or Shift + click to select multiple items. Typically, a set of check box options can provide similar, yet more accessible functionality.

How can we ensure our custom form controls are accessible?

The success criterion 4.1.2 for Level A compliance regarding name, role and value:

For all user interface components (including but not limited to: form elements, links and components generated by scripts), the name and role can be programmatically determined; states, properties, and values that can be set by the user can be programmatically set; and notification of changes to these items is available to user agents, including assistive technologies.

This success criterion is primarily for Web authors who develop or script their own user interface components. For example, standard HTML controls already meet this success criterion when used according to specification.

To better understand this success criterion it’s helpful to use examples. First off, when we develop custom controls we need to make sure that focus state and notification regarding change of focus is properly discoverable by user agents and assistive technology.

Another example would be that we need to make sure the selected state of a custom checkbox or radio item is properly implemented if we aren’t using the standard HTML controls. Similarly, the expand and collapse states should be apparent when building custom tree or list nodes.

Simply put, we need to ensure the custom components we use adhere to the same contract as their corresponding native HTML elements so that people using assistive technology can predictably interact with our applications.

Form submission

The success criterion 3.3.4 for level AA compliance regarding data submission:

For Web pages that cause legal commitments or financial transactions for the user to occur, that modify or delete user-controllable data in data storage systems, or that submit user test responses, at least one of the following is true:

  • Reversible: Submissions are reversible.
  • Checked: Data entered by the user is checked for input errors and the user is provided an opportunity to correct them.
  • Confirmed: A mechanism is available for reviewing, confirming, and correcting information before finalizing the submission.

The more strict 3.3.6 AAA standard is similar but has a wider scope of applicability. One of the above needs to be true for “Web pages that require the user to submit information”.

Some folks may be more likely to make mistakes when entering information in a form control. For example, people with motor skill impairment may hit keys by mistake and those with reading disabilities may interchange numbers and letters.

No matter what we do, mistakes will be made. How can we handle them?

There is a 3-step process for ensuring usable and accessible error recovery if either client-side or server-side validation detects errors in the form:

  1. Alert the user to the presence of the error in an apparent and accessible manner.
  2. Allow the user to easily access the form controls that need to be modified.
  3. Allow resubmission and revalidation of the form.

Here are a few mutually exclusive strategies we can use to satisfy these requirements.

Alert the user of an error then focus the respective form control

Advantage: users are informed of errors immediately and can then easily resolve the issue directly.

Disadvantage: only one error is indicated and addressed at a time.

Render all form errors on top of the form

We must provide a mechanism to quickly give our users access to the form control that must be remedied once the user has been presented with the associated error message.

We can provide a link within the error message that will set focus to the appropriate form control. While this can be done using client-side scripting, it’s typically easier and safer to simply provide a link that will set focus to the form control.

<a href="#input-id">Click me to focus on the input</a>
<!-- ... -->
<input id="input-id" type="text" aria-label="Test input">

Advantage: all errors are presented together.

Disadvantage: if there are multiple errors, it can be difficult for the user to remember, find, and address all of them.

Inline error designation

This designation can be accomplished via labeling or perhaps aria-describedby. It may be helpful to set focus to the first control that needs attention.

Advantage: errors appear in context with their respective controls.

Disadvantage: the user must visually scan or navigate through the form to discover the invalid controls and their respective error messages which can take some time.

So, which strategy should we use?

No one approach is best for accessibility, but there might be an optimal strategy based on the content, layout, and complexity of the forms they are applied to.

However, regardless of the mechanism used to identify and recover from form errors, aria-invalid="true" should generally be set on each invalid form control. This attribute causes screen readers to identify the control as being "invalid" or in need of attention.

If you walk away with nothing else

It’s important that we build our forms so that it’s as easy as possible for all users to successfully submit information.