From b145142404c203f697a7eebb7136358a8b1c391a Mon Sep 17 00:00:00 2001 From: TJ Date: Wed, 12 Aug 2026 10:23:37 -0700 Subject: [PATCH] fix(site): add aria-label to icon-only Back navigation links (#26222) ## Summary Two icon-only "Back" navigation links in the topbars have no accessible name. The visible tooltip text is wired via Radix's `aria-describedby`, which provides a *description*, not an accessible **name**, so screen readers announce them as just "link" with no purpose. This adds an `aria-label` to each link matching the visible tooltip text, following the existing `aria-label` convention already used in these same files (e.g. `aria-label="Create File"`, `aria-label="Daily usage"`). ## WCAG 2.1 criteria addressed - **SC 4.1.2 Name, Role, Value** (Level A) - **SC 2.4.4 Link Purpose (In Context)** (Level A) ## Changes | File | Element | Added | |---|---|---| | `site/src/pages/WorkspacePage/WorkspaceTopbar.tsx` | Back-to-workspaces chevron link | `aria-label="Back to workspaces"` | | `site/src/pages/TemplateVersionEditorPage/TemplateVersionEditor.tsx` | Back-to-template chevron link | `aria-label="Back to the template"` | No visual change. No behavior change for sighted users. `aria-label` is safe here because the elements have no visible text content (only an icon), so it is not overriding a visible name.
Why not rely on the existing Tooltip? Radix UI's `Tooltip` wires `aria-describedby` from the trigger to the tooltip content. `aria-describedby` provides an *accessible description*, not an *accessible name*. WCAG 4.1.2 requires interactive controls to have a programmatically determinable name, and screen readers do not consistently announce descriptions, especially when no name is present. Adding `aria-label` gives the link a stable, programmatic name that exactly matches the visible tooltip text.
--- _Created by Coder Agents on behalf of @tracyjohnsonux._ --- .../TemplateVersionEditor.stories.tsx | 12 +++++++++++- .../TemplateVersionEditor.tsx | 5 ++++- .../pages/WorkspacePage/WorkspaceTopbar.stories.tsx | 9 ++++++++- site/src/pages/WorkspacePage/WorkspaceTopbar.tsx | 2 +- 4 files changed, 24 insertions(+), 4 deletions(-) diff --git a/site/src/pages/TemplateVersionEditorPage/TemplateVersionEditor.stories.tsx b/site/src/pages/TemplateVersionEditorPage/TemplateVersionEditor.stories.tsx index 3004762e9c..2a7c171d3d 100644 --- a/site/src/pages/TemplateVersionEditorPage/TemplateVersionEditor.stories.tsx +++ b/site/src/pages/TemplateVersionEditorPage/TemplateVersionEditor.stories.tsx @@ -47,7 +47,17 @@ const meta: Meta = { export default meta; type Story = StoryObj; -export const Example: Story = {}; +export const Example: Story = { + play: async ({ canvasElement }) => { + const canvas = within(canvasElement); + const backLink = canvas.getByRole("link", { name: "Back to the template" }); + await expect(backLink).toBeVisible(); + await expect(backLink).toHaveAttribute( + "aria-label", + "Back to the template", + ); + }, +}; export const UndefinedLogs: Story = { args: { diff --git a/site/src/pages/TemplateVersionEditorPage/TemplateVersionEditor.tsx b/site/src/pages/TemplateVersionEditorPage/TemplateVersionEditor.tsx index 1aac65b885..5b505b95be 100644 --- a/site/src/pages/TemplateVersionEditorPage/TemplateVersionEditor.tsx +++ b/site/src/pages/TemplateVersionEditorPage/TemplateVersionEditor.tsx @@ -223,7 +223,10 @@ export const TemplateVersionEditor: FC = ({ - + diff --git a/site/src/pages/WorkspacePage/WorkspaceTopbar.stories.tsx b/site/src/pages/WorkspacePage/WorkspaceTopbar.stories.tsx index 6fd4ce86b6..5a14bf2a9b 100644 --- a/site/src/pages/WorkspacePage/WorkspaceTopbar.stories.tsx +++ b/site/src/pages/WorkspacePage/WorkspaceTopbar.stories.tsx @@ -54,7 +54,14 @@ const meta: Meta = { export default meta; type Story = StoryObj; -export const Example: Story = {}; +export const Example: Story = { + play: async ({ canvasElement }) => { + const canvas = within(canvasElement); + const backLink = canvas.getByRole("link", { name: "Back to workspaces" }); + await expect(backLink).toBeVisible(); + await expect(backLink).toHaveAttribute("aria-label", "Back to workspaces"); + }, +}; export const Outdated: Story = { args: { diff --git a/site/src/pages/WorkspacePage/WorkspaceTopbar.tsx b/site/src/pages/WorkspacePage/WorkspaceTopbar.tsx index 6d5a470cf6..9e0a3300fe 100644 --- a/site/src/pages/WorkspacePage/WorkspaceTopbar.tsx +++ b/site/src/pages/WorkspacePage/WorkspaceTopbar.tsx @@ -121,7 +121,7 @@ export const WorkspaceTopbar: FC = ({ - +