Jump to main content

Keep your labels clean

  • Published:
  • Category: accessibility

Providing contextual information within a form control’s associated label is a technique I’ve seen used to help make forms more accessible. This technique allows for form controls to have large hit areas to help those with motor disabilities, and ensure important instructions, or error messages, are announced to screen reader users.

For example:

<label>
  Username
  <input type="text">
  <span>Enter your customer ID or email address</span>
</label>

Pretty simple and a UX win for all, right?

Well, mostly…

While I’ve definitely used this technique in the past, it always felt a bit odd to me because it blurs the line between what the accessible name of the form control is, by including the instructions with it.

For example, with the above markup, screen readers would interpret the accessible name of the text field like this:

“Username Enter your customer ID or email address.”

While this example isn’t too bad, depending on the phrasing or length of the text, this technique could make for awkward announcements that could be handled more elegantly.

Clearing up labels with ARIA

Instead of adding instructional content to a form control’s associated label, the aria-describedby attribute could be used to reference the instructional content by it’s id. This would allow the accessible name of the form control to stay concise, while ensuring that screen reader users would be aware of, and have access to, the instructions while interacting with the form control.

For example:

<div class="example">
  <label for="my_input">
    Password:
  </label>
  <p id="my_input_desc">
    Passwords should be a string you will absolutely forget. 
  </p>
  <input type="password" 
    id="my_input" 
    aria-describedby="my_input_desc"
    name="formality_before_loading_the_captcha">
</div>

Passwords should be a string you will absolutely forget.

Now that we’ve given some meaningful instructions (sarcasm) on how to fill out the password field, all users will be able to remind themselves of why they need a password manager. Screen reader users will hear the announcement when tabbing into the form control, and will add a pause, or announce something like “edit”, between the accessible name of the form control, and its instructions.

The only issue here is that by placing these instructions between the label and the password field (which was done to ensure the instructions are not covered by a touch keyboard, when used on a mobile device), a hit area dead zone is created for users who benefit from larger click/tap areas to focus form controls. This isn’t ideal, and now it seems like we might have to go back to placing the instructions in the label, right?

Well, what if clicking or tapping the instructions move focus to the form control as well?

Your first thought might be “JavaScript to the rescue!” It wouldn’t be too difficult to create a click event on the instructions to move focus to the form control. Since an id and aria-describedby are already used on each element, referencing hooks could be used to make a pretty simple script.

But no. JavaScript is great, but we really don’t need it for everything.

CSS can do that!

Back at the start of 2018 Thierry Koblentz posted an interesting CSS technique to create large hit areas for links, without having to barrage screen reader users with a ridiculous amount of nested content. Edit: Peter Heery (@peterheery) noticed the BBC using a similar technique back in October 2017

To give you a quick idea of what it does, the technique utilizes the ::after pseudo element of the link, within a “card” markup pattern, to create an invisible hit area that covers the contents of the card. Allowing for a concise link announcement for screen reader users, and large click/tap areas for non-keyboard users. This sounds appropriate to what we need here…

Taking the password field markup pattern from earlier, we can repurpose this pseudo element technique, using the following CSS, to provide the label and input a larger hit area which will include the instructions:

First, keep the pseudo element relative to the label & form control’s container.

.hit-area {
  position: relative;
}

Use the label’s pseudo element to create a hit area that spans the full height and width of the wrapping element.

.hit-area label:after {
  content: "";
  height: 100%;
  left: 0;
  position: absolute;
  top: 0;
  width: 100%;
}

Set the input to be at a higher z-index than the pseudo element. We don’t want the pseudo element to get in the way of mouse users moving their insertion point (text cursor) within the input.

.hit-area input {
  position: relative;
  z-index: 2;
}

Here I just applied some light styling to visually differentiate the label and instructions.

.hit-area p {
  font-size: .75em;
  margin: .5em 0;
}

Now you should be able to tap or click on the label, or instructions to focus the input without needing to combine the accessible name and instructional text.

Passwords should be a string you will absolutely forget.

Screen readers will interpret the accessible name of the form control as “Password:”, while the instructions will be announced in the manner each screen reader conveys descriptive text.

If you want, you can also check out a demo on codePen where I’ve added a link into the description.

Wrapping up

I’m a bit of a stickler for semantics, so I realize that this may be more of an issue I wanted to solve, rather than something that needed to be solved. With that said, there are a few bits to this technique that may make it unsuitable for certain scenarios.

For instance, if you (unfortunately) have to support Internet Explorer, prior to version 11, then clicking pseudo element won’t move focus to the input. You would need to either go the JavaScript route, or include the instructions within the label for the larger hit area.

Additionally, more complex form control groupings (e.g. a group of multiple inputs within the same wrapping element) may make the larger hit area undesirable, as focus may move to an unintended input.