Latest Post: Integrating Large Language Models into Frontends

Accessible Forms (Part 1): Field Descriptions

How to really master the art of accessible forms

4 min read
Woman working in front of the computer with a lot of form inputs

This article is part of a series of articles about web accessibility with forms. In this first part, we will focus on how to make forms more accessible by providing field descriptions. In the next part, we will cover validation and errors with forms.

Accessible Forms

We know this, right? We all have had to deal with forms at some point in our lives. But have you ever thought about how difficult it can be for some people to fill out a form on a website? In this article, we are following the amazing article by Sandrina Pereira to learn how to make forms more accessible.

Some fundamental principles to keep in mind when designing accessible forms are:

  • Labels: Always use labels for form fields. This is important for screen reader users.
  • Error messages: Make sure error messages are clear and easy to understand.
  • Focus: Make sure the focus is visible and moves in a logical order.
  • Screen readers: Make sure that labels, error messages, and instructions are read out loud by screen readers.

So let’s dive into the details!

The fields

Example 1: Focus on one field

Remember to include the door and apartment.

Voiceover: Adress Remember to include the door and apartment, edit text

<form>
  <label for="address">Address</label>
  <input id="address" type="text" aria-describedby="addressHint"/>
  <span id="addressHint">Remember to include the door and apartment.</span>

  <button>Submit</button>
</form>

At this point, we could have some questions, like “Why did we use here aria-describedby?” and “What is the difference between aria-labelledby and aria-describedby?“.

In very short, and as Sandrina Pereira explains, we use aria-labelledby as an alternative to label and aria-label, that is, critical information for the user since it is the field’s accessible name. However, we use aria-describedby for additional information and it will be announced after the label with a slight pause between both.

Let’s see now another example! I want you to imagine you ask for a very weird company (soon you will find out why) and that you want to ask for some holidays.

Example 2: How To Deal With Complex Descriptions

Depending on how many days you choose, these will have consequences on your income, such as:

  • From 1 to 5: You will get extra 20% salary.
  • From 6 to 15: You will get extra 10% salary.
  • From 16 to 25: You will not get extra salary.
You can read the Holiday Program for detailed information.

Voiceover: 1, Number of holidays Below it’s explained how taking holidays influence your salary., stepper

<form>
  <label for="holidays">Number of holidays</label>
  <input id="holidays" type="number" value={1} aria-describedby="holidaysHint"/>

{' '}
<span class="field-hint">
  <span id="holidaysHint" hidden>
    Below it's explained how taking holidays influence your salary.
  </span>
  <span>
    Depending on how many days you choose, these will have consequences on your
    income, such as:
  </span>
  <ul>
    <li>From 1 to 5: You will get extra 20% salary.</li>
    <li>From 6 to 15: You will get extra 10% salary.</li>
    <li>From 16 to 25: You will not get extra salary.</li>
  </ul>
  <span>
    You can read the{' '}
    <a href="#fake-link" class="u-link">
      Holiday Program
    </a>{' '}
    for detailed information.
  </span>
</span>

  <button>Submit</button>
</form>

We get here some extra information for the screen reader that is visually hidden thanks to the hidden attribute. This works pretty well because it will only be read by the screen reader when the user is in the input. A question that might arise would be “Why did we not use the

.sr-only

class? Simply explained, that solution would also visually hide the text but will be read every time the user would go back and forward with the keys and would be redundant. We just want that to happen when being on the input.

If we want, we could even take a step further on this and show number of remaining days dynamically using aria-live=“polite” and using two references for the aria-describedby

Example 3: How To Deal With Complex And Dynamic Descriptions

Depending on how many days you choose, these will have consequences on your income, such as:

  • From 1 to 5: You will get extra 20% salary.
  • From 6 to 15: You will get extra 10% salary.
  • From 16 to 25: You will not get extra salary.
You can read the Holiday Program for detailed information.

You have 17 days remaining.

Voiceover: 8, Number of holidays Below it’s explained how taking holidays influence your salary. You have 17 days remaining., stepper

<form>
  <label for="holidays2">Number of holidays</label>
  <input id="holidays2" type="number" value={8} aria-describedby="holidaysHint2 remainingDays2" oninput="
    const totalDays = 25; 
    const remaining = totalDays - (this.value ? parseInt(this.value, 10) : 0); 
    document.getElementById('remainingDays2').textContent = 'You have ' + (remaining >= 0 ? remaining : 0) + ' days remaining.';"/>

{' '}
<span class="field-hint">
  <span id="holidaysHint2" hidden>
    Below it's explained how taking holidays influence your salary.
  </span>
  <span>
    Depending on how many days you choose, these will have consequences on your
    income, such as:
  </span>
  <ul>
    <li>From 1 to 5: You will get extra 20% salary.</li>
    <li>From 6 to 15: You will get extra 10% salary.</li>
    <li>From 16 to 25: You will not get extra salary.</li>
  </ul>
  <span>
    You can read the{' '}
    <a href="#fake-link" class="u-link">
      Holiday Program
    </a>{' '}
    for detailed information.
  </span>
</span>

{' '}
<span id="remainingDays2" aria-live="polite">
  You have 17 days remaining.
</span>

  <button>Submit</button>
</form>

This is all for the part 1 of this topic concerning accessible forms. In the next one I will try to cover validation and errors with forms.


Share article