Skip to content
easeweb
Search topics

Tree views keyboards can't open and screen readers flatten

A sidebar of sections and pages is built from clickable divs, or given tree roles without the keys, states and levels they promise, so the keyboard can't open its sections and a screen reader hears every item at the same level.

WCAG 2.2
SC 1.3.1ASC 4.1.2ASC 2.1.1A
Required by
Section 508 · EN 301 549 (EU)
Broken <div class="section">Account</div>
The accessibility problem illustrated: Motor:How do I open Account?
01

The problem

Keyboard users can't open a sidebar's sections to reach the pages inside them, and screen reader users can't tell which section a page is in, how deep it sits, or whether a section is open.

02

Try it

Open Account and reach Change your email using only the keyboard.

  1. Broken 1: press Tab. It stops only on the links already showing, never on a section, so Account can't be opened.
  2. Broken 2: the same divs, with tree roles added. Tab still skips every section, the arrow keys do nothing, and the panel says every item is level 1.
  3. Apply the fix. In the tree view, the arrow keys move and open sections, and Home and End jump to the ends.

Broken Can you fix this?

Screen reader says:

(Tab into the sidebar)

A recreated demo. The broken version is intentionally inaccessible.

03

The fix

Make every section a control that opens from the keyboard and says whether it is open, and put its pages inside it in the markup.

  1. 1Every section opens from the keyboard and says whether it is open.
  2. 2A page's section and depth are in the markup, not only in its indentation.
  3. 3A role="tree" gets everything the role promises, one Tab stop, the arrow keys, levels and states; without them, use lists and buttons.
Before

Sections built from clickable divs

<div class="help-nav">  <div class="section">Getting started</div>  <div class="pages" hidden>    <a href="/help/create-account">Create an account</a>    <a href="/help/invite-your-team">Invite your team</a>  </div>  <div class="section is-open">Billing</div>  <div class="pages">    <a href="/help/plans">Plans and prices</a>    <div class="section">Payment methods</div>    <div class="pages" hidden>      <a href="/help/cards">Cards</a>      <a href="/help/bank-transfer">Bank transfer</a>    </div>    <a href="/help/invoices">Invoices</a>  </div>  <div class="section">Account</div>  <div class="pages" hidden>    <a href="/help/change-email">Change your email</a>    <a href="/help/delete-account">Delete your account</a>  </div></div>
After

Nested lists with a button for each section

<nav class="help-nav" aria-label="Help topics">  <ul>    <li>      <button type="button" aria-expanded="false" aria-controls="help-start">Getting started</button>      <ul id="help-start" hidden>        <li><a href="/help/create-account">Create an account</a></li>        <li><a href="/help/invite-your-team">Invite your team</a></li>      </ul>    </li>    <li>      <button type="button" aria-expanded="true" aria-controls="help-billing">Billing</button>      <ul id="help-billing">        <li><a href="/help/plans">Plans and prices</a></li>        <li>          <button type="button" aria-expanded="false" aria-controls="help-payment">Payment methods</button>          <ul id="help-payment" hidden>            <li><a href="/help/cards">Cards</a></li>            <li><a href="/help/bank-transfer">Bank transfer</a></li>          </ul>        </li>        <li><a href="/help/invoices">Invoices</a></li>      </ul>    </li>    <li>      <button type="button" aria-expanded="false" aria-controls="help-account">Account</button>      <ul id="help-account" hidden>        <li><a href="/help/change-email">Change your email</a></li>        <li><a href="/help/delete-account">Delete your account</a></li>      </ul>    </li>  </ul></nav>

Why this fix: Use native HTML first

Fixing this with an AI coding assistant? Get this guide as Markdown, or get every guide in your coding agent.

04

Verify the fix

5 checks, no mouse.

Test with: Keyboard, Screen reader, Forced colors, Zoom

0 of 5 checked

Record the OS, browser and assistive-technology versions, the build, the date, and the actual result of each step. Repeat after the sidebar, its component or its library changes.

Limits

This is a starting pattern, not a guarantee for every application. The scripts are minimal sketches: the tree has no type-ahead, no multiple selection and no loading on demand. A dropdown menu across the top of a page is a different pattern, covered in dropdown menus that open only on hover, and a single section that opens and closes is covered in show and hide buttons that don't say whether they are open. A file tree that also lets people move items by dragging them needs a way without dragging, as drag-and-drop boards that only a mouse can use explains. Rows with several columns, such as an inbox of threads, are a tree grid, a pattern of its own. Test the complete journey with your target assistive technology.

This is a recreated teaching example, not a finding about a named client. The code is a starting pattern: test it in your own product. No completed assistive-technology test is claimed here.

Keep this fixed as your code changes.

Turn guides like this into rules your coding agents and CI follow, then have the result retested with a keyboard and screen readers.

How retests work