From 45e06f48a03354b600782259010ae6222241aff0 Mon Sep 17 00:00:00 2001 From: "Khai Shern, Toh" <55418374+Leos-Khai@users.noreply.github.com> Date: Mon, 21 Sep 2026 05:46:08 +0800 Subject: [PATCH] fix: composer hero reads project name to screen readers (#12397) --- .../features/threads/NewTaskDraftScreen.tsx | 2 +- .../src/components/chat/DraftHeroHeadline.tsx | 24 +++++++++++++++---- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/apps/mobile/src/features/threads/NewTaskDraftScreen.tsx b/apps/mobile/src/features/threads/NewTaskDraftScreen.tsx index 9732ed6865f54e6d459f76ba6d255eafa6f7d45a..681f6c5ee52d16ce253a59e34371ab247747bc73 100644 --- a/apps/mobile/src/features/threads/NewTaskDraftScreen.tsx +++ b/apps/mobile/src/features/threads/NewTaskDraftScreen.tsx @@ -1455,7 +1455,7 @@ export function NewTaskDraftScreen(props: { in + // The trigger's accessible name comes from its visible text (the + // project title) so the hero sentence reads naturally: an + // aria-label here would replace the title with an action phrase + // mid-sentence and baffle screen-reader users. + } > {activeProjectDisplayName ?? "Choose a project"} @@ -233,8 +234,21 @@ export function DraftHeroHeadline({ ); + // The composer hero is a sentence, so the heading's accessible name must be + // a complete sentence too. The project picker is a control rendered inline + // in the h1; without an explicit label its widget state bleeds into the + // announced phrase. + const headingLabel = hasResolvedProject + ? `What should we build in ${activeProjectDisplayName}?` + : canChooseProject + ? `${activeProjectDisplayName ?? "Choose a project"} to start` + : "Add a project to start"; + return ( -

+

{hasResolvedProject ? ( <>What should we build in {projectSelector}? ) : canChooseProject ? ( -- 2.54.0