From 420aa33cac69a092c19e85587f16f4f00a0ed891 Mon Sep 17 00:00:00 2001 From: l0ng-ai <24760907+l0ng-ai@users.noreply.github.com> Date: Wed, 30 Sep 2026 02:23:14 +0800 Subject: [PATCH] feat(a11y): expose Search Everywhere's results to screen readers Each row is a list option named by its title and subtitle, with the highlighted one selected. --- src/ui/search/view.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/ui/search/view.rs b/src/ui/search/view.rs index 193b4caf..c38e4152 100644 --- a/src/ui/search/view.rs +++ b/src/ui/search/view.rs @@ -330,6 +330,17 @@ impl ListDelegate for SearchDelegate { _window: &mut Window, cx: &mut Context>, ) -> Option { + let label: gpui::SharedString = match self.row_at(ix)? { + Row::Item(item) => match &item.subtitle { + Some(sub) => format!("{}, {sub}", item.title).into(), + None => item.title.clone().into(), + }, + Row::More { tab, hidden } => t_fmt( + L10nKey::SearchMoreIn, + &[("count", &hidden.to_string()), ("tab", tab.title())], + ) + .into(), + }; let content = match self.row_at(ix)? { Row::Item(item) => self.render_row(ix, item, cx), Row::More { tab, hidden } => h_flex() @@ -346,6 +357,7 @@ impl ListDelegate for SearchDelegate { }; Some(SearchRow { id: ("search-row", ix.section * 1000 + ix.row).into(), + label, selected: Some(ix) == self.selected, child: content, }) @@ -1235,6 +1247,9 @@ impl Render for SearchView { #[derive(IntoElement)] pub struct SearchRow { id: gpui::ElementId, + /// What a screen reader reads for the row: its title, and its subtitle + /// when there is one. + label: gpui::SharedString, selected: bool, child: gpui::AnyElement, } @@ -1256,6 +1271,9 @@ impl RenderOnce for SearchRow { let (hover, picked) = (gpui::rgb(sf.hover), gpui::rgb(sf.selected)); h_flex() .id(self.id) + .role(gpui::Role::ListBoxOption) + .aria_label(self.label) + .aria_selected(self.selected) .items_center() .flex_none() .h(px(ROW_H))