Search code examples
htmlaccessibilitywai-aria

Accessibility for slide-out sidebars


I'm currently focusing on accessibility for the sidebar I made for an App. It behaves as a "slide-out" meaning the content is still inside the dom, even when the sidebar is not visible. To ensure SR will not go through the sidebar when it's closed, I added a aria-hidden. Now, while adding aria-controls and aria-expanded to the button, i noticed this in the chrome DevTools (Elements > Accessibility):

Controls attribute empty

As the sidebar is aria-hiddened, the controls attribute is not linking correctly (which makes sense)

Following this logic, it links well when the sidebar is opened

enter image description here

Is this a sign that something is off ? This missing link is worrying me. If so, how should I fix this ?

Here's a demo of what i have (excuse the poor code, it's just for demo purpuse)

const control = document.querySelector("#control")

control.addEventListener('click', () => { 
  const aside = document.querySelector("#sidebar")
  let isSidebarHidden = aside.getAttribute('aria-hidden') === 'true'
  
  aside.setAttribute("aria-hidden", !isSidebarHidden);
  aside.classList.toggle("hidden")
  control.setAttribute("aria-expanded", isSidebarHidden)
  control.innerText = isSidebarHidden ? "close sidebar" : "Open sidebar"
})
aside {
  height: 100px;
  background: lightblue;
}

body {
  display: flex;
}

.hidden {
  visibility: hidden;
}
<body>
  <aside aria-hidden="false" id="sidebar">
    <div>Here comes the sidebar</div>
  </aside>
  <main>
    <button id="control" aria-controls="sidebar" aria-expanded="true">
      close sidebar
    </button>
  </main>
<body>


Solution

  • If the element isn't visible for anybody, you should use display:none rather than aria-hidden.

    The attribute aria-hidden should be used when an element has to be visible on screen, but hidden to screen readers and other assistive tools. This normally occurrs in relatively rare and precises circunstances only, for relatively small/short HTML code portions. If the element is hidden for everybody, regardless of the context, screen reader or not, then you should use CSS display:none or visibility:hidden.

    • CSS display:none ensure everything is properly hidden for everybody, regardless of the method used to use/navigate/operate the site/app. It behaves as the element wasn't in the DOM, meaning especially that none of the children can take focus (see below for more explanations)
    • As pair the first rule of ARIA, display:none is qualitively better than aria-hidden (the rule says: don't use ARIA, unless you really need to / there isn't any better alternative).

    When using aria-hidden instead of display:none, the element is hidden to screen readers and other assistive tools, but technically still visible on screen and operating as normal. This in particular means that focusable children continue to get the focus when navigating with tab.

    • For screen readers, this creates a contradiction: the focused element has to be announced, but shouldn't be announced because of aria-hidden. Additionally, focusable children are reachable with tab, but not with virtual/document cursor navigation using arrow keys. This leads to total incomprehention of the UI for the end user.
    • For keyboard only users, if something has to take focus while being off screen, whether it creates a weird visual effect, or nothing is visible at all and the user doesn't know where is the focus.

    Incorrect usage of aria-hidden is the root of many other problems.

    I have answered a similar question recently. I'm wondering why the tendance is to use aria-hidden instead of display:none, while it's a lot simpler and safer ?