Search code examples
htmlaccessibilityaccordionwai-ariasemantic-markup

How to make an accessible accordion using an hgroup?


I have an accordion in my app where each button has a heading and some supplementary information:

Screenshot of accordion

My initial implementation (which works fine) is as follows, but is not ideal from an accessibility standpoint as the <button> wipes out the "heading" role of the elements within it due to treating children as presentational (see discussion on this here and recommendations here).

<button type="button" aria-expanded aria-controls="region-id" aria-labelledby="title-id">
  <hgroup>
    <h3 id="title-id">Heading 1</h3>
    <p>Supplementary information 1</p>
  </hgroup>
</button>

According to the examples of accessible accordions that I've found (e.g. in ARIA Authoring Practices guide), the <button> should be contained inside the heading element. However I can't see how to do this without breaking up the hgroup and ending up with the supplementary information inside the heading element, e.g.

<h3>
  <button type="button" aria-expanded aria-controls="region-id">
    Heading 1
    <p>Supplementary information 1</p>
  </button>
</h3>

With the above approach, the <h3> element has the accessible name "Heading 1 Supplementary information 1" (incorrect), and the association of the supplementary information with the heading (previously provided by the <hgroup>) is missing.

Is there anything I can do here to have an accessible accordion while not having the supplementary information subsumed under the heading tag (and if possible grouped with an <hgroup>)?


Solution

  • To expand on Roland McLeod's comment, this can be achieved by structuring the DOM so that the hgroup contains the heading (with the button) and the supplementary text (outside of the button), and then using CSS to increase the clickable area of the button to include the supplementary text:

    <hgroup>
      <h3>
        <button type="button" aria-expanded aria-controls="region-id">Heading 1</button>
      </h3>
      <p>Supplementary information 1</p>
    </hgroup>
    
    hgroup {
      position: relative;
    }
    button::after {
      content: "";
      position: absolute;
      inset: 0;
    }
    

    This provides the desired user-experience while maintaining a semantically correct DOM.

    The technique of using CSS to expand a button's clickable area is described in articles here, here, and here.