Search code examples
htmldjangoaccessibilitywai-aria

In case of a Fieldset that is nested inside a Fieldset - how should the Legends be accessible to screenreaders?


I am working on a company's legacy code that has multiple instances where Fieldsets are inside of other Fieldsets. They have to adhere to accessibility for screen-readers and one of the issues that was found, is that the Legend of the first Fieldset, is not communicated as being related to the Labels of the radio buttons. This is part of a Django environment - it is part of nested custom template-tags and it's possible to change the nested Form inside the 'lowest/deepest' Fieldset, but seems impossible to try and pass the value of the highest Fieldset down to the nested componentns, but for now: this question concentrates on checking to see if the form is actually correct HTML.

Things I know:

  1. Some screen-readers do not read out the Legends, and therefor you have to repeat the Legend for each input Label in a span with a screen-reader only class.
  2. but: you are not supposed to simply just repeat the entire Legend text for each input, but instead use a short description that isn't too annoying when screenreaders read it.

Would this code be correct then?

  1. Or are all of those sr-only spans completely unnecessary?
  2. In the Django template I'm simply using the deepest Legend text as a variable that then can be used in the spans of each Label, and I have kept it short and called it 'Answer'. Is 'Answer' actually a good Legend text for accessibility or is it too generic?

I'm just not sure how to account for situations where some screenreaders will read the Legend, and others wont - or should we just use aria-label instead?

   <h1 class="h1">
   </h1>
   <p class="p">Answer these questions for help from the municipality.</p>
   <aside class="step-indicator" aria-label="Step indicator">
      <ol class="step-indicator__list">
         <li class="step-indicator__list-item step-indicator__list-item--completed P" data-step="1" aria-label="completed"><a href="/what-is-your-situation" class="link" aria-label="Situation"><span class="link-step__text">Situation</span></a></li>
         <li class="step-indicator__list-item step-indicator__list-item--active P" data-step="2" aria-current="step" aria-label="current step"><a href="/what-is-your-situation/how--would-you-like-to-gain-experience" class="link" aria-label="Job experience"><span class="link__text">Job experience</span></a></li>
      </ol>
   </aside>
   <fieldset class="questionnaire__fieldset">
      <legend class="h4" id="question">In which way would you like to gain job experience?</legend>
      <p class="p">Choose the answer that suits you best</p>
      <form class="form" method="POST" action="/what-is-your-situation/how--would-you-like-to-gain-experience" id="questionnaire_step">
         <input type="hidden" name="csrfmiddlewaretoken" value="999999999999x">
         <div class="form__control">
            <fieldset class="form__stack">
               <legend>Answer</legend>
               <div class="radio">
                  <input class="radio__input" type="radio" name="answer" value="5" id="id_answer_1"><label class="radio__label" for="id_answer_1"><span class="sr-only">Answer</span>I want to try and see if a job suits me.</label>
               </div>
               <div class="radio">
                  <input class="radio__input" type="radio" name="answer" value="6" id="id_answer_2"><label class="radio__label" for="id_answer_2"><span class="sr-only">Answer</span>I want to do volunteerwork</label>
               </div>
            </fieldset>
         </div>
         <input type="hidden" name="csrfmiddlewaretoken" value="999999999999x">
         <div class="form__actions ">
            <a class="button button--textless button--icon button--icon-before" href="/what-is-your-situation" title="Previous" aria-label="Previous">
            <span aria-hidden="true" class="material-icons ">arrow_backward</span>Previous</a>
            <button class="button button--textless button--icon button--icon-after button--primary" type="submit" name="" value="" title="Next" aria-label="Next">
            <span aria-hidden="true" class="material-icons ">arrow_forward</span>Next</button>
         </div>
      </form>
   </fieldset>
</div>```

Solution

  • In general, you should not worry about how different screen readers announce things provided you are using semantic HTML elements. In this case, nested <fieldset>/<legend> elements are perfectly valid even though some screen readers will announce only the nested legend for the inner elements but other screen readers will concatenate the inner and outer legends. That's really a decision for the screen reader vendor. Don't try to code around how things are announced.

    <fieldset>
      <legend>legend 1</legend>
      ...form elements...
      <fieldset>
        <legend>inner fieldset</legend>
        ...form elements...
      </fieldset>
      ...form elements...
    </fieldset>
    

    When I use your sample code, both JAWS and NVDA read both legends when I tab to the first radio button. They both announce almost exactly the same.

    JAWS

    "In which way would you like to gain job experience? group 
    Answer group
    Answer I want to try and see if a job suits me. radio button, not checked, 1 of 2"
    

    NVDA

    "In which way would you like to gain job experience?  grouping
    Answer  grouping
    Answer I want to try and see if a job suits me.  radio button, not checked, 1 of 2"
    

    When I tab to the second radio button, I do not hear the inner legend again because I already know I'm in a "group".

    Some screen readers will announce when you leave a "group" (fieldset), others don't. And some let you customize it via the "verbosity" settings.

    If my keyboard focus were after all the fieldsets and then I tabbed backwards to the last radio button, the outer and inner fieldsets would be announced again.

    I would recommend not having all the extra sr-only text on your radio buttons to force the legend announcement because with some screen readers, you'll hear your sr-only text and the legend text, so it'll be duplicated.

    In summary, you shouldn't have to do any extra work. Just nest your fieldsets correctly and let the screen reader do its thing.