Let’s review the following markup snippet, shall we?

<label for="name">
  Name <span>*</span>
<input type="text"  
       aria-label="Enter your name, required" 
       placeholder="Your name" 
       title="Enter your Name" 
<div id="msg" class="display-none">
  This field is required

Quite a few attributes there, huh? For those of you who know some of the ins and outs of web accessibility, you may have run into a similar looking markup pattern at one point or another. And, if you’re like me (sorry) you may be screaming (aloud or internally. it varies).

“What’s wrong with this?”, you who have been told they need to make their form fields accessible, wonder aloud. Your cat hears you, but they provide no commentary. Firstly, because cats have very little knowledge about web accessibility. Secondly, cats don’t talk. And thirdly, and most importantly, even if a cat did know about web accessibility and could talk, they wouldn’t offer any advice to you. Because they are a cat. They like to watch things suffer.

So, since the cat will never be of any help, ever, let’s fire up macOS’s built-in screen reader, VoiceOver (because let’s face it, you’re using a mac laptop right now, aren’t you?). With VoiceOver on, navigating to this field will announce the following:

“Enter your name, required, Your name, required, edit text. (pause) This field is required.”

For comparative purposes, here’s what NVDA on Windows 10 announces when navigating to the field:

“Enter your name, required. edit. required. invalid entry… This field is required. Your name.”

There sure are a lot of repetative announcements in there. Maybe this is why people say “the first rule of ARIA is don’t use ARIA”. But let’s be clear, even removing all the ARIA from the above snippet wouldn’t solve our redundantly verbose form field. Removing the aria-* attributes would just mean that the native HTML itself would be the sole culprit of our aural quagmire.

Wait…. but isn’t semantic HTML supposed to be accessible by default?

Breaking down to the essentials

Please note: I am not talking about form validation here, or the subject of live regions and their potential use to announce error messages for invalid form controls. That is not the purpose of this particular post. For some information on required/invalid states, you can read required attribute requirements. But again, that too is an article that has a specific purpose which may still not cover all of your questions about live regions and validation.

To understand why the form field is so chatty, we need to understand how the element and its attributes are exposed to assistive technologies, and what people actually need to know about the field to be able to interact with it.

Know your role

First, as we need users to be able to enter a string of text (in this case their name), we would use the <input> element. An <input> defaults to a type=text, regardless of whether the type attribute is specified or not.

<!-- or -->
<input type=text>

A role=textbox can be used on HTML elements to override the announcement of their native semantics, allowing that element to be announced as an “edit” or “edit text” field. However, as an <input> implicitly conveys this role, there is no need to explicitly specify it.

A name is not a sentence

But a role alone does not provide enough information on what this particular field is looking for a user to enter. This is where labeling / naming a field comes into play.

A text field can be named via one of the following methods:

  • aria-label or aria-labelledby attributes
  • <label> element
  • title attribute (if neither of the above two methods are used)
  • placeholder attribute (if none of the above three methods are used - also ew. this is a fallback for bad coding practices. don’t be bad.)

If a text field is provided a name via a <label> element, or one of the aria-label attributes, then title and placeholder attributes will shift in their responsibilities. The title providing a “description” for the field (more on this later), and the placeholder providing an “entry hint”.

Regarding this particular markup snippet, the <label>, aria-label, title and placeholder were all used, and all provided relatively similar content. That’s silly.

What this markup should have looked like is:

<label for="name">
  Name <span>*</span>
<input id="name" autocomplete="name" ...>

The <label> provides the concise accessible name for this text field - indicating the expected entry for the user is their “name”. (Note: being a text field that expects the name of the user filling out the form, an autocomplete="name" would also be expected to satisfy WCAG 1.3.5 Identify Input Purpose).

The use of aria-label="Enter your name, required" in the original snippet was unnecessary as there was already a concise <label> that provided the name to the text field. Additionally, the aria-label was doing more than just “naming” the field. It was adding unnecessary “instructions” such as “Enter your”, and indicating state (“required”). Being that the element is a text field, it is already understood that one would “enter” data into it. Much like if you were to give someone a sandwich, you would not say to them “here is a sandwich for you to shove into your mouth and chew.” The mouth shoving and chewing is understood, as you have already identified the item as a sandwich. People generally understand a sandwich is not footwear.

Continuing on the pathway of using common sense, we may now realize how unnecessarily redundant the title="Enter your Name" and placeholder="Your name" attributes are. If we nix those from our text field, we will have cut out one of our extra “Your name” announcements, and gotten rid of the unnecessary native tooltip that appears on mouse hover.

The remaining attributes

That still leaves us with aria-disabled=false, required, aria-required=true and aria-describedby attributes.

Using aria-disabled

First, the aria-disabled=false attribute does nothing in this situation. A text field can either be enabled (default state) or disabled, meaning it cannot be interacted with by users (and if natively disabled it will not submit its data upon form entry). Specifying aria-disabled=false is the same as if the attribute was not there… there’s no use case I can think of where this attribute/value would ever need to be explicitly declared.

Declaring a required state

Next, regarding aria-required=true and required, you only need one of these. Both attributes will expose the text field as being “required”. In reality, using the attributes together means that HTML required attribute would win out over the ARIA attribute, per ARIA’s rules concerning Conflicts with Host Language Semantics.

The reason the native HTML attribute overrides the ARIA version is due to the following reason:

When a host language declares a WAI-ARIA attribute to be in direct semantic conflict with a native attribute for a given element, user agents MUST ignore the WAI-ARIA attribute and instead use the host language attribute with the same implicit semantic.

The only ARIA attributes which are exempt from being ignored by similar HTML features are:

  • aria-label
  • aria-labelledby
  • aria-describedby

So, choose required or aria-required=true to indicate the field must be completed by the user. You don’t need both. Read this post for more information on which required attribute to choose.

Note that this also means we can clean up our label a bit, specifically the <span>*</span>. While the asterisk is commonly used to visually indicate a required field in a form, the text character itself can be announced by a screen reader in different ways, if announced at all. Since the field will already be announced as “required” due to the use of the aria-required or required attribute, this visual identifier could be consistently hidden by adding an aria-hidden=true to the containing <span>.

Describing an invalid entry

Finally, the aria-describedby in this situation is used to point to where a validation message would display. However, in this case the message is persistently in the DOM (though the container is set to display: none until it is needed). This, however, poses an issue as aria-describedby can still obtain a description from an element’s descendant text, even if that element is not presently rendered in the DOM.

So, to mitigate against this error message being constantly announced, the message area needs to be empty when its associated form field is not in error. OR, the aria-describedby attribute needs to only be added to the <input> element when the text field is in the invalid state.

Note: to differentiate this error message from a general descriptive text string, and to help ensure it does not potentially fail WCAG 1.4.1 Use of Color (by using the color red, alone, to indicate this text represents an error message), the text “Error:” has been added to the start of the message.

Note 2: because aria-describedby takes precedent over title attribute, the title that was specified on the initial snippet would not end up being announced at all. If this were to have been an actually useful instance of a title attribute, this would have been an issue (lol. oh goodness that was a ridiculous sentence to type. a useful title attribute… sigh).

Wrapping up

After giving the initial markup snippet a good scrub, getting rid of all the unnecessary attributes, the resulting markup would resemble the following:

<label for="name">
  Name <span aria-hidden="true">*</span>
<input id="name" aria-required="true" aria-describedby="msg" autocomplete="name">
<div id="msg">
  <!-- the following is only added to the DOM when needed -->
  Error: This field is required

VoiceOver would announce the above as “Name, required, edit text” (and if in error would only then add “Error: this field is required” as its description).

NVDA would announce “Name, edit, required, invalid entry has autocomplete”. Also, if found to be invalid, the error description would then be announced. Other PC screen readers would announce similarly.

What I hope you take from this is that it’s not just unnecessary ARIA that can make web content overly verbose and redundant. Rather, unnecessary and misused HTML can make for awful aural experiences as well. Being percise with our markup, and knowing how each element and attriube we specifiy will contribute to the way an element is exposed to assistive technologies is impariative in creating accessible and inclusive user experiences.