Home > front end >  How to structure aria/accessibility on complex nested form structure in HTML?
How to structure aria/accessibility on complex nested form structure in HTML?

Time:06-25

I have a somewhat complex "nested" form structure, which I'm doing sort of like this:

<form>
  <h2>Word Dictionary Entry</h2>
  <div class='field'>
    <label for="nameInput">Word</label>
    <input id="nameInput" name="word" />
  </div>
  <div class='field-group-container'>
    <label>Meanings</label>
    <div class='field-group'>
      <label>Meaning 1</label>
      <div class='field'>
        <label for="meaning1_sense1">Sense 1.1</label>
        <input id="meaning1_sense1" />
      </div>
      <div class='field'>
        <label for="meaning1_sense2">Sense 1.2</label>
        <input id="meaning1_sense2" />
      </div>
      <button>Add sense</button>
    </div>
    <div class='field-group'>
      <label>Meaning 2</label>
      <div class='field'>
        <label for="meaning2_sense1">Sense 2.1</label>
        <input id="meaning2_sense1" />
      </div>
      <div class='field'>
        <label for="meaning2_sense2">Sense 2.2</label>
        <input id="meaning2_sense2" />
      </div>
      <button>Add sense</button>
    </div>
    <button>Add meaning</button>
  </div>
</form>

Basically it is a form for like creating a Google dictionary entry, such as this one:

enter image description here

This is not an image of a form, but the output you could generate from such a form.

For each 1, 2, 3, ..., those are "meaning items". Then for each meaning item, there are multiple "senses", which are slight variations on the base meaning. So in this image, for the term/word "process", there are 3 meanings, the first of which has 5 senses, and the other two meanings only have 1 sense each.

  • meanings
    • meaning 1
      • sense 1.1
      • sense 1.2
      • sense 1.3
      • sense 1.4
      • sense 1.5
    • meaning 2
      • sense 2.1
    • meaning 3
      • sense 3.1

I could go one layer deeper than that even, and say that a sense has multiple associated "concepts", but I won't take it that far for this post. Just know that the nesting isn't limited to 3 levels.

The question is, how should you structure the form so it is accessible? The higher-level "labels" probably shouldn't be labels, or should they? Where should I actually use the label tag in this scenario, and what should I use from aria-roles to properly annotate this nesting?

CodePudding user response:

To structure forms, the <fieldset> element along with a <legend> should be used.

This element has a group role, which will not add this structure to the document outline, and screen readers will announce when focus enters or leaves the group, so it’s not read all the time.

<form>
  <h2>Word Dictionary Entry</h2>
  <div class='field'>
    <label for="nameInput">Word</label>
    <input id="nameInput" name="word" />
  </div>
  <fieldset class='field-group-container'>
    <legend>Meanings</legend>
    <fieldset class='field-group'>
      <legend>Meaning 1</legend>
      <div class='field'>
        <label for="meaning1_sense1">Sense 1.1</label>
        <input id="meaning1_sense1" />
      </div>
      <div class='field'>
        <label for="meaning1_sense2">Sense 1.2</label>
        <input id="meaning1_sense2" />
      </div>
      <button>Add sense</button>
    </fieldset>
    <fieldset class='field-group'>
      <legend>Meaning 2</legend>
      <div class='field'>
        <label for="meaning2_sense1">Sense 2.1</label>
        <input id="meaning2_sense1" />
      </div>
      <div class='field'>
        <label for="meaning2_sense2">Sense 2.2</label>
        <input id="meaning2_sense2" />
      </div>
      <button>Add sense</button>
    </fieldset>
    <button>Add meaning</button>
  </fieldset>
</form>

There is another question to answer: How do you tell screen reader users that their new item has been added?

One solution might be to focus the new input directly, which will announce the new element and the new group it is in.

addMeaning.addEventListener('click', () => {
  // add new fieldset…
  // focus the first input in the new fieldset
  newFieldset.querySelector('input').focus();
});

How one would go about deleting a meaning or sense is not clear from your question.

  • Related