Search code examples
htmlaccessibilitywai-aria

How to make related checkboxes accessible using wai-aria tags?


I have the following code in my DOM:

<fieldset> 
  <legend id="language-legend">What languages do you know?</legend>
  <p id="language-description">
    You can select one or more.
  </p>
  <div class="form-check">
    <input name="language" class="form-check-input" type="checkbox" value="python" id="language-checkbox-1" aria-labelledby="label-1 language-legend" aria-describedby="language-description">
    <label id="label-1" class="form-check-label" for="language-checkbox-1">
      Python
    </label>
  </div>
  <div class="form-check">
    <input name="language" class="form-check-input" type="checkbox" value="javascript" id="language-checkbox-2" aria-labelledby="label-2 language-legend" aria-describedby="language-description">
    <label id="label-2" class="form-check-label" for="language-checkbox-2">
      JavaScript
    </label>
  </div>
  <div class="form-check">
    <input name="language" class="form-check-input" type="checkbox" value="c++" id="language-checkbox-3" aria-labelledby="label-3 language-legend" aria-describedby="language-description">
    <label id="label-3" class="form-check-label" for="language-checkbox-3">
      C++
    </label>
  </div>
</fieldset>

I am doing the following:

  • Using <fieldset> with <legend> to group related checkboxes
  • Each checkbox has the same name, ie, name="language"
  • Each checkbox is labelled by the <legend> and the actual <label> element using the aria-labelledby tag.
  • Each checkbox is described by the <p> using the aria-describedby tag.

Am I using all of the aria tags correctly? Is this form field fully accessible?

EDIT

Gemini suggested the following re-write:

Excessive aria-labelledby:

  • It's generally redundant to include both the <legend> and the individual <label> elements in aria-labelledby for each checkbox. The <legend> already provides a group label for all checkboxes within the <fieldset>.
  • Rely on visual association for screen readers to infer the relationship between checkboxes and the legend.

Move aria-describedby to <fieldset>:

  • The description applies to the entire group of checkboxes, not each checkbox individually.
  • Place aria-describedby="language-description" on the <fieldset> element instead of each checkbox.
<fieldset aria-describedby="language-description"> 
  <legend>What languages do you know?</legend>
  <p id="language-description">
    You can select one or more.
  </p>
  <div class="form-check">
    <input name="language" class="form-check-input" type="checkbox" value="python" id="language-checkbox-1">
    <label class="form-check-label" for="language-checkbox-1">
      Python
    </label>
  </div>
  <div class="form-check">
    <input name="language" class="form-check-input" type="checkbox" value="javascript" id="language-checkbox-2">
    <label class="form-check-label" for="language-checkbox-2">
      JavaScript
    </label>
  </div>
  <div class="form-check">
    <input name="language" class="form-check-input" type="checkbox" value="c++" id="language-checkbox-3">
    <label class="form-check-label" for="language-checkbox-3">
      C++
    </label>
  </div>
</fieldset>

Is this actually better?


Solution

  • Yes, the code from Gemini is better for accessibility.

    Adding too much of aria-* is an overkill. ARIA is best used for accessibility when the HTML markup is unable to provide good accessibility.

    Your code has the right semantic HTML which is good enough for accessibility.

    • Your checkboxes have labels,
    • grouped under a fieldset,
    • with legend and paragraph description.

    This is good semantic HTML instead of using plain divs and spans.


    Adding too much aria-* will result in the screen reader repeating excessive info and might result in hearing fatigue for the end user. The info conveyed to the user must be short, precise and understandable so that they can achieve their task without wasting time.

    Now imagine a screen reader user using your site. For your markup the following is roughly what the screen reader will read out loud,

    1. What languages do you know?
    2. You can select one or more.
    3. Input Checkbox - Python - What languages do you know? - You can select one or more.
    4. Input Checkbox - JavaScript - What languages do you know? - You can select one or more.
    5. Input Checkbox - C++ - What languages do you know? - You can select one or more.
    

    The end user will hear redundant information, it wastes their time and doesn't add more value/help to the task they are trying to achieve on your site. Listening to What languages do you know? You can select one or more four times consecutively can easily cause hearing fatigue.

    Now Gemini's markup will be read out somewhat like below,

    1. What languages do you know?
    2. You can select one or more.
    3. Input Checkbox - Python
    4. Input Checkbox - JavaScript
    5. Input Checkbox - C++
    

    which is short, crisp, and easily understandable. The screen reader user can quickly achieve their task (interact with this form) and move on with their next task.


    Your usage of semantic HTML is good, which is enough for accessibility. Extra aria is not required. I would suggest to even remove aria-describedby attr from Gemini's markup.

    aria-describedby is best applicable when the description element is far away in the DOM, like maybe a deeply nested descendant, or a sibling element, a hidden element, or even elements that do not share a common ancestor. You can use such unrelated elements as description with aria-describedby.

    But in your markup, the description element <p>, immediately follows the legend which will be read out loud by the screen reader, in that order, which is once again a good use and structuring of semantic HTML. But if you want to still add a description on fieldset then the above aria-describedby is fine.


    For better accessibility, try to experience your site like your end user, in this case like a screen reader user. VoiceOver/TalkBack can be enabled from Accessibility settings (all major platforms have this now) and go through your site and see if any text read out loud is too much info or do you experience hearing fatigue on any repeated information...