Online forms are the foundation of communication in the modern age. Without forms, all we'd have would be static text websites with pictures of cats to look at. Sure, it doesn't sound too bad, but without forms, how would we discuss and share cat pictures with all our friends and family? How about shopping online, booking a flight, ordering pizza late at night, or setting up a time to meet on that dating site?
This is why well-written form structure and design is critical to the success of any website or app. Let's take a look at a few areas on how we can increase accessibility when it comes to form design.
Highly visible, clear, and precise form labels are critical to the success of anyone being able to fill out a form. Without a label, no one would know what the intended purpose for each form field would be!
Let's look at a few design considerations when adding labels to our forms.
HTML form fields feature an attribute called
placeholder. The value of the attribute places text inside the field and, when someone starts to type, the placeholder text is automatically removed.
The original purpose of this attribute is to place helper or hint text inside the
input. However, sometimes placeholders are being used in place of an actual HTML
label element. This is problematic for a few reasons:
- Without a
labelelement associated with the
input, some screen readers may not be able to convey the purpose of the
- When someone starts to type and the
placeholdertext is removed from view, the context of the
inputmay be lost, forcing someone to remove the entered text in order to remember what the
- In order to meet color contrast requirements, the default grey text needs to be darkened. In doing so, this may confuse some people into thinking that text has already been entered into the
There are more issues with the
placeholder attribute, but with these few in mind, it's clear that
placeholder should not be used as a replacement for an actual
The "floating label" technique seems to be picking up in popularity as of late. Depending on how it's implemented, the basic idea is to use CSS to position the
label (or sometimes the
placeholder) text over-top of the related
input element. When someone starts typing, the
label text is "floated" up and placed above the input.
The benefit of this approach is that it saves space in-between inputs when screen real estate is tight. There's also the clear benefit of a
label element being associated with its
input element for screen readers to convey the purpose of the
The downside to this approach is a direct result of its purpose of being; when the
label is floated up above the
input, the space available typically only allows for less than ideal text size. This could result in difficulty reading the label text for anyone with low-vision. Of course, they could just zoom in on the screen, but why require creating more work for our users?
Then the other concern regards the actual implementation. If the technique ends up using the
placeholder attribute instead of an actual
label, it would result in issues previously discussed, mainly the lack of conveyed purpose when interacted with a screen reader.
The ideal design of form labels when it comes to accessibility is the "always visible" label. Just as it sounds, this technique features a text label that is always present across the whole experience of filling out the form.
The benefits of this approach are quite clear:
- The text label is in a consistent, predictable position
labelis always visible, requiring no cognitive load of having to remember the input purpose
- Screen readers will convey the purpose of the
inputwhen interacted with label text is large with ample white space to be readable
With all this in mind, it's strongly recommended to keep labels visible. Eliminate any guesswork required from your users and allow them to complete the task at hand with ease and confidence.
Visually hidden labels
One more label type we need to discuss is the "visually hidden" label. These often appear in tiny, one-off form inputs such as Search or Language selector components where space is limited.
As we know, form
input elements must always include a
label in order to share its purpose with the user. What can we do when a design calls for a non-visible
label? Let's review how to apply a visually hidden label in two different ways, each method leading to the same outcome in the end.
Note: Voice dictation users may have difficulty finding the correct call-to-action when accessing each control with a visually hidden label. Proceed with caution.
.visuallyhidden class definition (also sometimes called
.sr-only) directly to the
label element will remove the label for sighted users, but remain available for screen reader users.
<label for="lang-selector" class="visuallyhidden">Select a language</label> <select id="lang-selector"> <!-- ... --> </select>
Another option is to apply the
aria-label attribute directly onto the
input element in order to provide a "hidden" label.
<select aria-label="Select a language"> <!-- ... --> </select>
Just like the
.visuallyhidden approach, this will provide a
label for the
input and, on
input focus, the
aria-label value will be announced by screen readers.
When only specific fields are Required or Optional to fill out a form, it's best to denote this requirement with visual and audible cues. This helps people to know which fields they absolutely need to fill in which, in turn, provides reassurance when filling out the form.
When marking as Required, this is typically done with an asterisk character or an icon placed beside the form
label. Whether you use the asterisk or some other form of an icon, what's important here is:
The placement of the icon is consistent throughout the form
The icon features a contrast ratio high enough to be visible (
3.0:1for non-text elements)
<label for="email"> Email <svg class="required-icon" role="presentation" aria-hidden="true" focusable="false" … > <!-- … --> </svg> </label>
When marking a field as Optional, placing this context as plain text within the
label will suffice.
<label for="email">Email (Optional)</label>
In order to notify a screen reader user of a required field, we can simply add the
aria-required attribute to the
input element. This will inform the user that this field is required, but does not add anything else in terms of field validation.
<label for="email">Email</label> <input type="email" id="email" name="email" aria-required="true" />
When a screen reader encounters this
input, it may announce something like, "Email, edit text, required."
In addition to the visual cue for each required field beside the
label text, it's also best practice to place instructions at the top, notifying the user of each field type. Something along the lines of:
<!-- When marking as Required… --> <p aria-hidden="true">* denotes a required field</p> <!-- When marking as Optional… --> <p>All fields required unless described otherwise.</p>
With this plain text note, people with cognitive impairments, older generations, or someone new to the internet will have less trouble with understanding which fields are mandatory, and as a result, spend less time and effort on filling out the form.
Now, as a developer you may be thinking, "Why not just use the built-in HTML
required attribute? Doesn't this also announce a required field?"
It's true that including the
required attribute renders a similar result to using
aria-required, notifying the screen reader user of a required field. The difference is using
aria-required allows the developer to include custom validation rules.
Avoid native validation
Using custom validation instead of the built-in browser validation is strongly preferred for a few reasons:
- Greater control over error messaging
- Messages can be translated into multiple languages
- Consistent and predictable messaging implementation
- Messages are not removed from view after a short period of time
For these reasons, it is strongly recommended to implement custom form validation.
WCAG success criteria
This comes back to 3.3.2 Labels or Instructions which states:
"Labels or instructions are provided when content requires user input."
The design of form error messages can be quite delicate. The idea is to bring awareness to the current state of the form without being overwhelming. Unfortunately, it's very easy to cause frustration or grief when displaying error states, especially for those who aren't so tech-savvy and who are already very cautious and on edge from using a computer in the first place.
As designers and developers, it's our responsibility to ease our users into the systems that we create, guiding their way through the path we've set forth before them.
With this in mind, let's consider a design aesthetic which is informal and does its best not to be overbearing at the same time.
Three things to look at in this section include:
- Error text
- Input styles
- Error list
Error text is critical when conveying an error state. Without this text, people might not realize that the form is in a state in which it cannot be submitted. Sure, we could change the color of the
input element, perhaps alter its
background properties to something recognizable as an error state. However, as we've already seen, relying on color alone to convey meaning is not ideal.
So, how do we ensure the input error state is properly conveyed? A few things we can do are:
- Output text which is meaningful and does not overwhelm the user with technical jargon (cognitive impairment).
- Display the text below the related input (low-vision).
- Ensure text is readable by testing its color contrast.
- Optionally include an icon to help bring the users attention to the text.
Connecting error text to its input
When someone using a screen reader comes in contact with an
input element in an error state, this information needs to be announced alongside its
label text. Otherwise, there's a good chance the error context could be lost when navigating through a form.
There are a few ways to accomplish this, but the most robust would be to include the
aria-describedby attribute on the
input element. Adding this attribute places the error text in the "queue" of announcing the element on keyboard focus.
In order to programmatically make the connection, the
aria-describedby value needs to match the
id of the error text container.
For example, let's review an
input element in an error state.
<label for="fname">First name</label> <input type="text" id="fname" name="fname" /> <span id="error-fname" class="error">First name is required</span>
input features a
label and some error text directly below. However, the text is not included with the announcement of the
label as there's no programmatic connection being made.
Let's make the connection using
aria-describedby, an attribute which is used to help provide more information for the given context.
<label for="fname">First name</label> <input type="text" id="fname" name="fname" aria-invalid="true" aria-describedby="error-fname" /> <span id="error-fname" class="error">First name is required</span>
aria-describedby attribute applied to the
input, and its value matching the
id of the error text container, the announcement from a screen reader would sound like,
"First name, invalid, edit text. First name is required."
One of the benefits of using
aria-describedby specifically is that it adds a short pause in between the
label text and the error text, giving it a little bit of a distinction in the announcement.
Presenting a list of error when a form is in an error state is particularly useful on large forms. This content is made up of a heading, explaining the current state of the form, followed by an unordered link list.
The heading, typically an
focus() method as well as applying
tabindex="-1" to the heading element in order for it to receive focus.
The list portion is made up of a
ul element containing links. Each link represents a single error in the form. The link text should match that of the error text output below the related
input. When activated, the keyboard focus would switch from the link to the related
input, allowing the user to focus on and address the issue at hand.
<h2 class="form-message__title" tabindex="-1"> Please adjust the following: </h2> <ul> <li> <a href="#fname" class="form-message__link"> First name is required </a> </li> <!-- ... --> </ul> <!-- ... --> <label for="fname">First name</label> <input type="text" id="fname" name="fname" aria-invalid="true" aria-describedby="error-fname" /> <span id="error-fname" class="error">First name is required</span>
The ideal positioning of the error list is directly above the form which is for user convenience. For example, if someone using a screen reader were to move forward past the error list, they would be brought to the form with its
input elements. Each
input would be accompanied by their own error state text which would inform the user on how to adjust the
input content to meet its validation requirements.
The error list, in combination with the error text below the
input, ensures the user is notified of the current errors which need attention and removes the cognitive load of not having to remember each error which needs fixing; the error message will be available when they arrive at the
WCAG success criteria
This comes back to 3.3.1 Error Identification which states:
"If an input error is automatically detected, the item that is in error is identified and the error is described to the user in text."
Just as important, but sometimes forgotten about, is the success message. When someone completely fills in the form correctly, there should be text set in place to notify the user of the current state.
As with the error list heading, the success message should also be designed to include large, attention-grabbing text. In addition, the keyboard focus should be managed on behalf of the user and set on the success message heading element. With this, the user will be informed of the form submission and can confidently move onto another task.
The HTML autocomplete helps users to complete filling in forms by using data stored in the browser. This is particularly useful for people with motor disabilities or cognitive impairment who may have difficulties filling out forms online.
For example, a form input asking for someone's email address wound need to include the
autocomplete attribute in order to send a hint to browser or other user agents to query for this data:
<label for="email">Email</label> <input type="email" id="email" name="email" autocomplete="email" ... />
With this in place, users will have a much easier and comfortable user experience when their browser of choice prompts them to enter their email address on their behalf.
Review the section, "W3C HTML 5.12 – 184.108.40.206. Autofill" for all other input types and their corresponding autocomplete attribute values.
Inline validation and the Submit button significance
In modern form design and development, especially common in SPA app demos, there are two trends in particular: inline-validation of form controls after they've been "touched" (essentially when the user moves away from the
input) and keeping the Submit button in a disabled state (via
disabled attribute) until each validation test has been satisfied.
When it comes to creating highly usable and accessible forms, particularly for people with disabilities, it is recommend not using inline validation. This pattern has the potential to cause the user a bit of confusion or frustration at times. Some examples illustrating this include:
- When someone using a screen reader is navigating through a form to get a lay-of-the-land overview, trying to read what each field is and the expected data
- Someone who might want to fill in form fields in a different order
- When someone leaves a field to go look something up to be certain of what data to place within the form control
These simple actions trigger the error message and the result can be quite irritating
During usability studies, people often grumble or curse out loud when error messages appear before they've even started filling out forms!
Additional accessibility issues appear when the user navigates away from a field; the error message is displayed visually but, typically, not to assistive technology. In order to hear the error message, the user needs to navigate backward through the form. This would be an unexpected required action to hear and understand the error state.
With the Submit
button set as
disabled by default, only after all of the form validation rules have been satisfied does the control become available for use. Having this pattern in place might lead to a confusing or frustrating user experience; there's no indication as to why the control would be disabled after filling in the form on first pass.
Consequently, disabled controls can present two additional challenges for individuals:
- People who have low vision might not be able to perceive the button text in the dimmed state.
- Some assistive technology will skip
disabledelements; screen reader users may not get a full picture of what is available in the interface, leading to feelings of uncertainty or self-doubt.
Accounting for accessibility with this pattern
To alleviate some of these potential pain points for users, its recommended to take a slightly different, hybrid approach. Consider making the following changes to your form workflow:
- When an
inputis in an error state, output the error message text as described previously. This will serve as a reminder of the error and the expected value when the control is navigated to, as well as any other controls in an error state when the user moves forward through the form content.
- When the user moves away from the form
input, run the validation test. If the test fails, output the error text visually for sighted users but refrain from announcing the new state to screen reader users.
- When typing in an
inputwhich is in an error state, remove any error text; only display error text when focus moves away from the
- Allow full form validation to run on form submission by keeping the Submit
buttonenabled. This will allow the user to easily explore the form and become comfortable with the form structure on the first run through. Even if the form fields have errors, allow users to submit the form on their terms, when they feel comfortable to do so.
With these changes in place, anyone relying on assistive technology or those who require a little more guidance in completing a form will have a clearer understanding of how the form is structured and the current state of the form, as well as if there are any errors and how to address them.
If there are changes to be made on submit, focus will be brought up to the error list. From there, error links will move focus directly to the form
input in question. From this point, error messages will be announced when traversing the form, and any changes to the data can easily be made with greater confidence on the part of the user.