From de837e268381eaa0e9b72fe8718de40f5ac66973 Mon Sep 17 00:00:00 2001 From: Evyatar Bluzer Date: Thu, 2 Jul 2026 04:32:49 +0700 Subject: [PATCH] refactor(a11y): issues view toggle aria attributes and goal tree expand buttons (#1939) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Thinking Path Two interactive UI controls were missing WAI-ARIA attributes, so screen-reader users couldn't perceive their state. The IssuesList view-mode toggle already had `title` tooltips but no `aria-label`/`aria-pressed` and its container had no `role="group"`; the GoalTree expand/collapse chevron announced only "button". Approach: attributes only, no logic/render changes, reusing the pattern already shipped on the Agents page toggle. Per review feedback, GoalTree uses a **stable** `aria-label` (`` `${goal.title} subtree` ``) with `aria-expanded` for state, rather than a dynamic label that double-announces state. ## Issue _No existing tracking issue — described inline per CONTRIBUTING.md → "Link Issues or Describe Them In-PR"._ **What happened** Two components expose buttons with no accessible name or state, making them unusable via screen reader: (1) the `IssuesList` view-mode toggle doesn't convey which view is active; (2) the `GoalTree` expand/collapse chevrons have no name and no expanded/collapsed state. **Expected behavior** Both controls announce their purpose and current state to assistive technology. **Steps to reproduce** Enable VoiceOver, open the Issues page and Tab to the view-mode toggle, then open the Goals page with nested goals and Tab to a tree chevron — each control announces only "button", with no name and no pressed/expanded state. ## What Changed **`ui/src/components/IssuesList.tsx`** — `role="group"` + `aria-label="View mode"` on the container; `aria-label` ("List view"/"Board view") and `aria-pressed` on each button. **`ui/src/components/GoalTree.tsx`** — stable `aria-label` (`` `${goal.title} subtree` ``) and `aria-expanded` on the chevron button. 2 files, ARIA attributes only, no behavioral change. ## Verification 1. Issues page → toggle announces "List view, pressed" / "Board view, not pressed", grouped as "View mode". 2. Goals page with nested goals → each chevron announces " subtree" with expanded/collapsed state. 3. Manual VoiceOver pass; no visual/behavioral change for sighted users. ## Risks Minimal — additive HTML attributes with no impact on logic, rendering, or state. Worst case is a suboptimal announcement string, trivially adjusted. ## Model Used Original change human-authored by @bluzername. Two follow-up commits (stable `aria-label` refinement; removal of a stray tooling file) applied via maintainer edit; the refinement was drafted with Claude Opus 4.8. ## Checklist - [x] I searched the GitHub PR list (open + recently closed) for similar/duplicate PRs before opening — none found. --------- Co-authored-by: Andrew Aymeloglu --- ui/src/components/GoalTree.tsx | 2 ++ ui/src/components/IssuesList.tsx | 6 +++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/ui/src/components/GoalTree.tsx b/ui/src/components/GoalTree.tsx index 116b1668f2..6c0de3cccd 100644 --- a/ui/src/components/GoalTree.tsx +++ b/ui/src/components/GoalTree.tsx @@ -35,6 +35,8 @@ function GoalNode({ goal, children, allGoals, depth, goalLink, onSelect }: GoalN e.stopPropagation(); setExpanded(!expanded); }} + aria-label={`${goal.title} subtree`} + aria-expanded={expanded} > {/* View mode toggle */} -
+
@@ -1400,6 +1402,8 @@ export function IssuesList({ className={`p-1.5 transition-colors ${viewState.viewMode === "board" ? "bg-accent text-foreground" : "text-muted-foreground hover:text-foreground"}`} onClick={() => updateView({ viewMode: "board" })} title="Board view" + aria-label="Board view" + aria-pressed={viewState.viewMode === "board"} >