The Anatomy of an Accessible Text Field

Posted on

Forms are complicated. Or rather, forms consist of so many parts that they're easy to get wrong. Talking from experience: the odds of a website with forms having accessibility issues are nearly guaranteed. The limited automated test of the WebAIM Million already finds issues with labels on nearly half of all pages.
Let's find out what we can do to avoid these and many other issues with forms. We're going to dissect the most common form-specific element: the text field.

This article gives you a starting point for designing and coding text fields. The solutions given are not the only way to meet accessibility requirements and user needs, but they do offer a solid and proven approach. These examples should help you meet compliance with WCAG 2 AA.
A form can consist of many more parts. This article does not focus on other elements or form validation. It touches upon a lot of WCAG criteria already, just by dissecting an invalid required text field.

The result

This is the "too long; didn't read"-version of this article. The resulting code should be something like this:

<label for="text-field">[Descriptive name] (required)</label>
<span id="hint">Put your instructions here</span>
<input type="text" id="text-field" aria-required="true" aria-invalid="true" aria-describedby="hint error" autocomplete="[to be determined]"></input>
<span id="error" role="alert">⚠️ The required field "name" is empty.</span>

Which should result in something with visuals like these:

The result of the mentioned code. A label, a hint, a text field and an error message

Your version will probably look different when it comes to things like fonts, spacing and colours. Consider this a wireframe more than a visual design.

The elements

Let's go through all the parts that make up a text field.

The label

<label for="text-field">[Descriptive name] (required)</label>

The label is the element, both visually and in code, to name an element.

Action without a name, a who attached to it, is meaningless.

― Hannah Arendt

Everything needs a name. A name helps you identify an element. It helps you distinguish one from another. It can tell you what its purpose is. It also tells you how to refer to an element. Common labels include texts like "Name", "Password" and "Email".
WCAG SC 3.3.2 Labels or Instructions requires you to provide labels or instructions when user input is required. In theory, this could be any <span> or <div>. WCAG SC 1.3.1 Info and Relationships requires that it's marked up properly. The most appropriate element to do that with is the <label>-element.
Visually, a label and a text field should have a clear relationship. By adding the for-attribute, you create a relationship between the <label> and the <input> in the code as well (which satisfies WCAG SC 1.3.1). This works by using the id of the <input> as a value. Added bonus, the label is now interactive. When activated, the focus is put on the text field.
By creating this relationship, you also give the text field an accessible name. Naming a text field is needed for WCAG SC 4.1.2 Name, Role, Value. Using this method to name a text field results in the visible label being the same as the name in the code. This satisfies WCAG SC 2.5.3 Label in Name.
There is also a success criterion related to the size of interactive elements. By making the label at least 24 by 24 pixels, you won't have to consider WCAG SC 2.5.8 Target Size (Minimum).

As you might expect from what's written so far, the label needs a nice descriptive name. This is also mentioned in WCAG SC 2.4.6 Headings and Labels. It does not need to be unique across pages. It does need to be consistent to satisfy WCAG SC 3.2.4 Consistent Identification.
For this example, we assume the text field is required. This is the ideal location to visually indicate a text field is required. A simple "(required)" is a great way to do this. This is much easier to understand than an asterisk (which might introduce new issues).

The hint or instructions

<span id="hint">Put your instructions here</span>

Form fields often, but not always, have additional information. This could be about the expected format of the input, like how to format a date. It can also state specific requirements, like the number of characters in a password.
Any additional information, besides the name/label, that is known before the user provides input, should be put into this area. This means you should state password requirements before validation. This avoids frustrating guessing games where users provide input, they get feedback, they adjust their input, they get new feedback, they adjust their input again, and so forth. Such an opaque feedback loop makes a form unusable.
Like the label, instructions can help satisfy WCAG SC 3.3.2 Labels or Instructions.

The text field

<input type="text" id="text-field" aria-required="true" aria-invalid="true" aria-describedby="hint error" autocomplete="[to be determined]"></input>

We add type="text" to declare this input to be a text field. There are different values that might be relevant for you. Use type="password" for a password that will be obscured. If you can add a button to toggle visibility of a password, that's great. I wish this were a WCAG-requirement and/or implemented in all browsers.
Watch out with values like type="number" as they can limit the keyboard that is shown on mobile and can introduce different interactions like spinners.
The id is important. We've used that value in the for-attribute of our label. That's how we've created a relationship in our code.
aria-required is a way to indicate this field is required. It is also mentioned in WCAG as Technique ARIA2:Identifying a required field with the aria-required property. It's related to WCAG SC 1.3.1 Info and Relationships, WCAG SC 3.3.1: Error Identification and WCAG SC 3.3.2 Labels or Instructions. Unlike the HTML-attribute required, aria-required does not trigger built-in validation messages.
Likewise, aria-invalid can be used to indicate an invalid field. This is mentioned in WCAG as Technique ARIA21:Using aria-invalid to Indicate An Error Field and is related to WCAG SC 3.3.1: Error Identification.
aria-describedby adds a description to the text field. Screen readers often pronounce this (or these) after the essential name, role and values of an element. The attribute takes an "ID reference list" which means it can concatenate multiple IDs. In this case we refer to the hint or instructions, and any error message that might be present. We do this with WCAG SC 1.3.1 Info and Relationships in mind.
The autocomplete-attribute helps people input information they have used before. It identifies what type of input is expected. All possible autocomplete-values are listed in the specification. If there is no fitting value, consider using on instead. This way a tool like a browser or password manager can still attempt to assist the user, but it might use other metrics or information besides the autocomplete-value.

And whatever you do, don't use placeholders. Placeholders in Form Fields Are Harmful.

The error message

<span id="error" role="alert">⚠️ The required field "name" is empty.</span>

The error message needs an id so it can be referred to by aria-describedby. We do this for WCAG SC 1.3.1 Info and Relationships. The role="alert" gives the <span> semantics, and is there to announce the error much like aria-live would do. This makes sure errors are harder to miss, and helps with WCAG SC 4.1.3 Status Messages.
Then there's the content itself. Often we start with an icon, pictogram or whatever image. A lot of people appreciate visual cues like these. Making sure to give them an alternative where needed (WCAG SC 1.1.1 Non-text Content). Preferably something that describes what the image communicates (a word like "error" or "warning") and not a description of the image.
An image also helps with WCAG SC 1.4.1: Use of Color. It avoids a form field where only colour differentiates a state like an error.
There's a book to be written about what makes an error message good. As a starting point, don't tell the user anybody they (could) know already and support them in fixing the issue. This means it should be human-readable, helpful and rules out issues with formatting. The formatting can be communicated beforehand.

Other considerations

There are considerations for the visual design as well. Hopefully obvious are WCAG SC 1.4.3 Contrast (Minimum) and WCAG SC 1.4.11: Non-text Contrast. Both text and non-text should have sufficient contrast. This is another reason to avoid placeholders.
The order of elements in this article is not accidental. Putting label and instructions first reduces the odds of people missing them before reaching a text field. This assumes using a left-to-right language. It also avoids an on-screen keyboard blocking this information when inputting information.
Make sure elements are grouped close together. When they're far apart, they're easy to miss for people zooming in (both digitally and using a magnifying glass).
When text fields are used to input information that needs to be verified, like a validation code through SMS, make sure verification happens after submission. Pages that "change on their own" can be very confusing and conflict with WCAG SC 3.2.2: On Input
While this article focuses heavily on web and HTML, the same principles apply for mobile and native code.

Conclusion

Forms can be extensive. They're fragile when it comes to both Web Accessibility and Usability. Both many things can be done wrong, and many parts can be built better than how other build forms.
The text field specified here is your starting point. Take this and iterate on it for your own use cases. Improve and adjust when you are certain you need to deviate. Otherwise take this example as your accessible default.
A form field is much more than just text fields, but you can't build accessible forms when the building blocks fail already. Solidify your foundation before building further.

Get the best support. Let's assess your needs, and we will find the best way to meet them!

Contact us