Search code examples
htmlaccessibilityuser-experiencesemantic-markup

Is there a way to place the open/close button of a navigation menu outside the nav element without hurting accessibility?


I couldn't find a clear answer/explanation to this question so far.

This seems uncontroversial from an accessibility perspective:

Example A:

<header>

  <!-- Other stuff like a logo or other buttons -->

  <nav>
    <button>Menu</button>

    <ul>
      <li><a href="">Page 1</a></li>
      <li><a href="">Page 2</a></li>
      <li><a href="">Page 3</a></li>
    </ul>
  </nav>
</header>

However from a UI design perspective, this may be limiting. It would be liberating to have a markup like this:

Example B:

<header>

  <!-- Other stuff like a logo or other buttons -->

  <button>Menu</button>

  <nav>
    <ul>
      <li><a href="">Page 1</a></li>
      <li><a href="">Page 2</a></li>
      <li><a href="">Page 3</a></li>
    </ul>
  </nav>
</header>

In either case, if the navigation was closed, the nav element would not have to be hidden, it would be enough to hide the ul element using display none.

Although in example B, hiding the nav element (i.e. the entire navigation) might be better from a UX perspective, since a closed navigation without an open/close button as a child might be confusing, but I am not sure.


Solution

  • Short Answer

    Option 1 is better as the semantics make relationships obvious. Option 2 can be made just as accessible with aria attributes (assuming they are supported by the users screen reader and browser combo).

    Choose option 1 unless there is absolutely no way to achieve your desired design with positioning etc. (which I would argue is very rare!)

    Longer Answer

    80%+ of accessibility is semantics and semantic relationships.

    In your first example the button to control the menu is part of the navigation, which makes perfect sense. This has the added benefit of making any focus trapping and management if this is a modal type menu (you didn't specify but the pattern suggests it might be) a lot easier.

    In your second example, having an empty <nav> element as you have hidden the <ul> is not ideal as navigating by landmarks could still lead some screen readers to show that landmark, so when a user navigates to it they would find it is empty.

    The other option is to hide the <nav> element entirely which is also not ideal as when navigating by landmarks there would be no <nav>.

    If you want to use the second mark-up despite these drawbacks WAI-ARIA can help with defining the relationship between the button and the menu etc.

    By using aria-haspopup and aria-owns on the <button> (don't forget aria-expanded but that one is needed for both examples).

    Please note: aria-controls is actually the more appropriate aria attribute instead of aria-owns, but support is not great for aria-controls sadly.

    Final thoughts

    Yet again you did not specify if this is a modal type menu, but I am assuming it is from the pattern.

    As such you need to consider focus trapping and making it clear that the menu button acts as both an open and a close button depending on the menu state. For that you could use some visually hidden text within the button to indicate the state, which is better than relying on aria-expanded alone:

    <!--closed state-->
    <button aria-expanded="false"><span class="visually-hidden">Open </span>Menu</button>
    <!--opened state-->
    <button aria-expanded="true"><span class="visually-hidden">Close </span>Menu</button>