AFTER
Keyboard: Tab to enter · ↑/↓ move · → expand · ← collapse · Enter open
Interactive demo
BEFORELooks like a tree, but it’s just focusable rows with click handlers.
▸ src
▸ components
• TreeView.jsx
• Tabs.jsx
• App.jsx
• README.md
Selected: src
What’s broken:
- No tree semantics (
role="tree"/role="treeitem"), so assistive tech can’t announce structure. - Every row is a Tab stop (too many stops).
- No arrow-key navigation; no expand/collapse semantics.
AFTERRoving tabindex + arrow keys +
aria-expanded on parent nodes.
src
(folder)
components
(folder)
TreeView.jsx
(file)
Tabs.jsx
(file)
App.jsx
(file)
README.md
(file)
Focused: src. Expanded. Use ↑/↓ to move.
Try:
↓ to move · → on a folder to expand · ← to collapse · Home/End jump · Enter “open” an item (announcement only).
Checklist (what the AFTER version adds)
- Semantics:
role="tree",role="treeitem", androle="group"for children. - State:
aria-expandedon expandable nodes only. - Keyboard: ↑/↓ move between visible items; → expands or moves into children; ← collapses or moves to parent.
- Roving tabindex: only one treeitem is Tab-focusable at a time.
- Predictable focus: collapse a folder keeps focus on that folder (doesn’t “teleport” focus).
- Announcements: a polite status line for “opened” items (so screen readers get feedback without spam).
This is a compact demo, not a full file explorer. Real apps may also support typeahead, multi-select, or context menus — but the core is still semantics + roving focus + predictable expand/collapse.