Repro (gpui-component at rev 94a313a, v0.6.0 line; still present at v0.6.6 — list.rs:668-669):
v_flex()
.key_context("List")
.id("list-state")
.track_focus(&self.focus_handle) // focusable tab stop …
// … but no `.role(...)` → no accessibility node is painted
List renders a focusable container (track_focus + id) without a role. gpui skips painting the a11y node for roleless focusables (gpui::window::a11y logs: "focused element (FocusId(..)) has no accessibility node (it has an id but no role); assistive technology will announce the whole window instead. Give it both an .id(...) and a .role(...) to expose it.").
Consequences, observed live (headless sway, app with a searchable List in its tab chain):
- Tab reaches the container, and focus "disappears": no node is exposed, so assistive tech announces the whole window.
set_focus never resolves (nodes.focus stays unset), so any focus reporting built on gpui's a11y debug dump reports gpui_focus: null for that stop.
Suggested fix: paint a role on the container, e.g.
v_flex()
.key_context("List")
.id("list-state")
.track_focus(&self.focus_handle)
.role(Role::List) // ← node now exists; focus maps
...
(Note Role::GenericContainer is not an option — gpui debug-asserts it is filtered out of the a11y tree.)
Verified downstream that the element is the container (not a child): tab-order position matches the List's paint position, and adding roles to our own root containers removed every other instance of the log line except this one.
Repro (gpui-component at rev
94a313a, v0.6.0 line; still present at v0.6.6 —list.rs:668-669):Listrenders a focusable container (track_focus+ id) without a role. gpui skips painting the a11y node for roleless focusables (gpui::window::a11ylogs: "focused element (FocusId(..)) has no accessibility node (it has an id but no role); assistive technology will announce the whole window instead. Give it both an.id(...)and a.role(...)to expose it.").Consequences, observed live (headless sway, app with a searchable
Listin its tab chain):set_focusnever resolves (nodes.focusstays unset), so any focus reporting built on gpui's a11y debug dump reportsgpui_focus: nullfor that stop.Suggested fix: paint a role on the container, e.g.
(Note
Role::GenericContaineris not an option — gpui debug-asserts it is filtered out of the a11y tree.)Verified downstream that the element is the container (not a child): tab-order position matches the
List's paint position, and adding roles to our own root containers removed every other instance of the log line except this one.