Forms

Forms are a vital way for users to interact with websites; ensuring forms are accessible benefits everyone.

Summary

Submitting a query, placing an order, sharing a comment: these are all important ways that users expect to be able to connect with us and each other through our websites. This is not surprising, since web forms have been part of the World Wide Web definition nearly as long as there has been a World Wide Web. [1] They are one of the best understood and most robust user-interaction technologies on the web. Where there are issues is typically down to us: either by misunderstanding and misapplying the standard, or by trying to reinvent conventions that are already accessible without considering every use case.

Meaningful, visible text labels

Meaningful, and visible labels for form control elements are important for all users and can increase understanability for users with visual or reading disabilities, and those with cognitive disorders. They are required for screen readers and allow users who navigate by speech recognition applications to correctly identify the form elements on the screen.

<form class="wont-submit">
<div class="form-row">
<label for="name">Name</label>
<input id="name" name="name" class="form-control" type="text">
</div>
</form>

Screen reader: "Name, edit text"

A placeholder is not a label

HTML label elements and the input placeholder attribute do not serve the same purpose and cannot be used interchangeably. Labels are text in your HTML document and don't become invisible as soon as you start interacting with the input they describe. Neither of those things are true for placeholder text. There is ample explanation from experts showing how, in addition to being inaccessible, attempting to use a placeholder as a label is unusable for many.

Alternatives to a visible label

In some cases, for very simple forms that may consist of only an input and button for example, the button text can stand in for the visible label. Here a visually-hidden class (from Bootstrap) provides the accessible name for screen readers.

<form role="search" class="wont-submit">
<div class="input-group">
<label for="search-terms-ex1" class="visually-hidden">Search our site.</label>
<input id="search-terms-ex1" class="form-control border-dark" type="search" enterkeyhint="Search">
<div class="input-group-append">
<button class="btn btn-dark" enterkeyhint="Search" type="submit">Search</button>
</div>
</div>
</form>

Screen reader: "Search our site., search text field, search"
Screen reader: "Search, button"

In the demo several accessibility-related attributes are applied to improve accessibility.

  • role="search" - when applied to a form, creates a Search landmark within the document, enabling assistive technology users to more efficiently navigate to the search feature on the page.
  • type="search" - identifies an input that is equivalent to one of type text, but which may be optionally be styled differently by the web browser.
  • enterkeyhint="Search" - provides an additional affordance where the name displayed on the ENTER key of any onscreen keyboard (for example when entering text on a mobile phone touchscreen) is customised from the usual value of, for example "Go", to a more appropriate in this case value: "Search".

Using a button icon

There are only a few cases where an icon is conventional enough that it could be used to visually label a form input, the "magnifying glass" icon however is a very established affordance and so is an exception.

<form role="search" class="wont-submit">
<div class="input-group">
<label for="search-terms-ex2" class="visually-hidden">Search our site.</label>
<input id="search-terms-ex2" class="form-control border-dark" type="search" enterkeyhint="Search">
<div class="input-group-append">
<button class="btn btn-dark" enterkeyhint="Search" type="submit">
<svg class="icon" aria-hidden="true" focusable="false" role="img">
<use xlink:href="#icon-search"></use>
</svg>
<span class="visually-hidden">Search</span>
</button>
</div>
</div>
</form>

Screen reader: "Search our site., search text field, search"
Screen reader: "Search, button"

Don't hide the search text input field. While a search form may use up valuable space, for many users it's the most efficient and accessible means of locating the content they came to your website to find. Trying to shrink the entire search form down into just an icon has been shown to make it harder to recognize and less usable for all users, including those with disabilities. [2]

Use autocomplete

Input fields that collect user information can be automatically filled in by web browsers through autocomplete.

If you are collecting personal information, such as their given name, family name or similar [3] include an explicit autocomplete attribute with a value indicating which value to automatically add.

<form novalidate class="wont-submit">
<div class="form-row">
<label for="first-name" class="form-label">First Name</label>
<input type="text" autocomplete="given-name" id="first-name" name="first-name" class="form-control">
</div>
<div class="form-row">
<label for="last-name" class="form-label">Last Name</label>
<input type="text" autocomplete="family-name" id="last-name" name="last-name" class="form-control">
</div>
</form>

Indicate required input

It is common to mark the labels of required form fields with an asterisk (or "star") character as a concise visual cue that those fields must not be left empty. While this is conventional, it can seem strange for a screen reader user to hear "Choose a username star". I tend to use CSS to add the asterisk as visual-only content using the "content alternative text" [4] set to an empty string. This will keep most screen readers from saying "star". As an alternative, use the aria-required="true" attribute on the input element to enable screen readers to announce "required".

.mark-required::after {
content: "*";
content: "*" / "";
opacity: 0.64;
}
<form novalidate class="wont-submit">
<div class="form-row">
<label for="username" class="form-label mark-required">
Choose a username
</label>
<input name="username" id="username" class="form-control" type="text" aria-required="true">
</div>
</form>

Screen reader: "Choose a username. required, edit text."
Screen reader: "You are currently on a text field. To enter text into this field, type."

Don't rely on paragraph text at the top (or even worse, at the bottom) of a form stating that "all fields are required". Screen reader users may use the tab key to quickly navigate through forms, moving directly from one input element to another. Any extraneous text not associated with an input will likely never be heard.

Validation

Good client-side validation will improve the user experience, reduce server load, and can make it easier for users to see why errors happened.

The aria-invalid="true" attribute on an HTML form control will cause a screen reader to announce "invalid" when that element gets focus. This is useful for users who cannot see visual indicators marking a field as invalid, but is only helpful once focus is moved to the invalid field.

Validation feedback

You must provide users with feedback regarding the results of form validation, whether it was successful or unsuccessful. This must include visible text feedback, identifying and explaining any errors. Inline feedback should be provided near form controls. If there are multiple input fields, a second overall feedback message displayed near the top of the form, or near the submit button, can also be useful.

In the previous example the HTML element with ID "username-hint" didn't seem to be doing very much. It is acting as a description for the input element via the aria-describedby attribute, but in the initial rendering of the form it is empty. We intend to use that element to communicate any notifications associated with the User name field once that field becomes invalid. In any other state it is left empty.

Once the form submit is activated then client-side form validation can run. Don't attempt to validate each input as the user works to complete the form. It can be annoying or disorienting for screen reader users, or users with certain cognitive issues, to be presented with feedback notifications on every keystroke.

When the user attempts to submit a form, and errors are found, a general error message may appear near the submit button, making it visible to the user without the need for scrolling.

Error messages should stand out clearly from the rest of the form content but don't rely only on colors or icons: always include a visible text message that communicates what each error is. It can help screen reader users identify error messages if the message itself is prefixed with the word 'Error'.

<div class="form-row">
<label for="userage" class="form-label mark-required">
Your age
</label>
<input type="text" name="userage" id="userage" class="form-control userage-input" aria-required="true" aria-describedby="userage-error" onblur="validateUserage(this.form)">
<div id="userage-error" class="invalid-feedback form-error userage-error beak-box beak-top" aria-live="assertive"></div>
</div>

Screen reader: "Your age, required, edit text"
Screen reader: "Error: your age is required"
Screen reader: "Your age, required invalid data, edit text"

Don't disable the submit button

The conventional cue to sighted users that a button is disabled requires that it is noticeably lower in contrast than a non-disabled button. Lowering contrast can make the button text unreadable for users with low vision or other impairments. This may be acceptable if the button is not intended to be perceived by users, but a form submit button should be perceivable by every user.

Even for users that can perceive a lower-contrast disabled submit button, it would be confusing if that submit button were inoperable without some specific explanation of why. If the form will not submit until a client-side validation check, add text explaining this near the submit button rather than disabling the button.

Don't rely on built-in HTML5 validation

You may have noticed that each form HTML element in the examples so far have a novalidate attribute. This is intended to disable the built-in HTML5 form validation. While it might seem that built-in validation would be an accessible technique to rely upon, in fact the implementation is inconsistent across browsers, and has definite accessibility failings in some.

HTML5 gives us form field validation for free. The problem is that the default messages browsers provide are not always useful and typically do not work with assistive technology. [5]

Certain combinations of web browser and assistive technology result in problems with disappearing error messages and messages that ignore user zoom-levels. For these reasons we recommend disabling the built-in validation using the novalidate attribute, and implementing your own well-tested and accessible client-side validation notifications instead.

HTML5 input types

The introduction of HTML5 brought several new form input types, intended to make it easier to enter specific kinds of form data like email, date or tel. Web browsers that support these input types can provide an optimized interface for collecting that type of data: a phone number pad, or a calendar date-picker for example. Additionally, web browsers can provide more appropriate auto-fill suggestions based on the input type and name attributes.

For many users, including disabled users, these accommodations can improve their experience, making it faster and easier to complete a form -- in some cases the browser can fill the form out for them. But you should never force users to interact with form controls in only that way. Wherever possible allow users to enter text by typing. Ensure that a date can be entered as simple text for example, even if a date-picker is available to use.

Screen reader: "Your age, required, stepper"
Screen reader: "You are currently on a stepper. To begin interacting with this stepper, press Control-Option-Shift-Down Arrow."

Checkpoints for the Tester

  1. All form fields that take user input or display content must have an accessible name.
  2. All form fields that take user input must have a visible label; this label must be visible in all states, and therefore the placeholder attribute is not suitable for displaying a text label.
  3. Additional descriptions, for example the format expected for form field input, must be programmatically associated with the form field and should be visible at all times.
  4. A field element in an invalid state should have aria-invalid="true", and aria-invalid="false" once the invalidity is corrected. Do not apply an aria-invalid attribute until the field has been interacted with; a field should not have this attribute at page load.
  5. Error messages must be programmatically associated with the form field in error.
  6. Error messages must be removed as they are corrected.

Notes and references

  1. RFC 1866, Hypertext Markup Language - 2.0, November 1995 "Section 8, Forms", T. Berners-Lee and D. Connolly back to reference 1

  2. "This design was problematic because it made the search less visible and forced users to click on the magnifying glass icon to expand the search box. Users had to then click again to set their cursor’s focus in the search box to type their keywords." Intranet-Search Essentials Nielsen Norman Group back to reference 2

  3. W3C Input Purposes for User Interface Components back to reference 3

  4. "Alternative text may be specified for an image (or list of content items) by appending a forward slash and then the text. The alternative text is intended for speech output by screen-readers, but may also be displayed in some browsers. Note that if the browser does not support alternative text, neither the content or alternative text will be used." mdn web docs Support 71.91% global. back to reference 4

  5. Avoid Default Field Validation, Adrian Roselli back to reference 5