From 4e2640e506f323fe4c968f57d0673ecdf9e66e64 Mon Sep 17 00:00:00 2001 From: Jaayden Halko Date: Fri, 13 Mar 2026 17:47:53 +0700 Subject: [PATCH] =?UTF-8?q?fix(site):=20WCAG=202.1=20AA=20remediation=20?= =?UTF-8?q?=E2=80=94=20landmarks,=20semantics,=20and=20a11y=20tooling=20(#?= =?UTF-8?q?22746)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary Targeted WCAG 2.1 AA accessibility remediation — continuation of #22673 — addressing remaining semantic, landmark, and tooling gaps identified in the frontend accessibility review. ### Changes #### Document semantics (WCAG 3.1.1) - **`site/index.html`**: Added `` root wrapper so screen readers and browser features correctly identify the document language. #### Landmark & bypass (WCAG 1.3.1, 2.4.1) - **`DashboardLayout.tsx`**: Replaced `
` with `
` so assistive technology exposes a proper main landmark and the skip link targets a semantic region. #### Table header relationships (WCAG 1.3.1) - **`Table.tsx`**: `TableHead` now renders `scope="col"` by default (overridable via prop), giving data cells an explicit header relationship. #### Semantic interactive controls (WCAG 2.1.1, 4.1.2) - **`AuditLogRow.tsx`**: Replaced `
` with native `
diff --git a/site/src/modules/management/DeploymentSettingsLayout.tsx b/site/src/modules/management/DeploymentSettingsLayout.tsx index da14a24753..d52e52d253 100644 --- a/site/src/modules/management/DeploymentSettingsLayout.tsx +++ b/site/src/modules/management/DeploymentSettingsLayout.tsx @@ -54,11 +54,11 @@ const DeploymentSettingsLayout: FC = () => {
-
+
}> -
+
diff --git a/site/src/modules/management/OrganizationSidebarLayout.tsx b/site/src/modules/management/OrganizationSidebarLayout.tsx index 6113235be3..ee8803686e 100644 --- a/site/src/modules/management/OrganizationSidebarLayout.tsx +++ b/site/src/modules/management/OrganizationSidebarLayout.tsx @@ -7,11 +7,11 @@ const OrganizationSidebarLayout: FC = () => { return (
-
+
}> -
+
); }; diff --git a/site/src/pages/AuditPage/AuditLogRow/AuditLogRow.tsx b/site/src/pages/AuditPage/AuditLogRow/AuditLogRow.tsx index 946e21aad0..a49b04394d 100644 --- a/site/src/pages/AuditPage/AuditLogRow/AuditLogRow.tsx +++ b/site/src/pages/AuditPage/AuditLogRow/AuditLogRow.tsx @@ -15,9 +15,10 @@ import { TooltipTrigger, } from "components/Tooltip/Tooltip"; import { InfoIcon, NetworkIcon } from "lucide-react"; -import { type FC, useState } from "react"; +import { type FC, type KeyboardEvent, useState } from "react"; import { Link as RouterLink } from "react-router"; import userAgentParser from "ua-parser-js"; +import { cn } from "utils/cn"; import { buildReasonLabels } from "utils/workspace"; import { AuditLogDescription } from "./AuditLogDescription/AuditLogDescription"; import { AuditLogDiff } from "./AuditLogDiff/AuditLogDiff"; @@ -75,16 +76,22 @@ export const AuditLogRow: FC = ({
{ - if (event.key === "Enter" || event.key === " ") { - event.preventDefault(); - toggle(); - } - }} + className={cn( + "flex flex-row items-center gap-4 py-4 px-8", + shouldDisplayDiff && "cursor-pointer", + )} + {...(shouldDisplayDiff && { + tabIndex: 0, + role: "button", + "aria-expanded": isDiffOpen, + onClick: toggle, + onKeyDown: (event: KeyboardEvent) => { + if (event.key === "Enter" || event.key === " ") { + event.preventDefault(); + toggle(); + } + }, + })} >
diff --git a/site/src/pages/AuditPage/AuditPage.test.tsx b/site/src/pages/AuditPage/AuditPage.test.tsx index 04be04aa11..7f0b0cebe2 100644 --- a/site/src/pages/AuditPage/AuditPage.test.tsx +++ b/site/src/pages/AuditPage/AuditPage.test.tsx @@ -8,13 +8,7 @@ import { waitForLoaderToBeRemoved, } from "testHelpers/renderHelpers"; import { server } from "testHelpers/server"; -import { - createEvent, - fireEvent, - screen, - waitFor, - within, -} from "@testing-library/react"; +import { screen, waitFor, within } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { API } from "api/api"; import type { AuditLogsRequest } from "api/typesGenerated"; @@ -91,47 +85,53 @@ describe("AuditPage", () => { audit_logs: [MockAuditLog], count: 1, }); + const user = userEvent.setup(); await renderPage(); const row = screen.getByTestId(`audit-log-row-${MockAuditLog.id}`); const expandableRowButton = within(row).getByRole("button"); + expect(expandableRowButton).toHaveAttribute("role", "button"); + expect(expandableRowButton).toHaveAttribute("tabindex", "0"); + expect(expandableRowButton.tagName).toBe("DIV"); expect(screen.queryByText(/ttl:/i)).not.toBeInTheDocument(); - fireEvent.keyDown(expandableRowButton, { key: "Enter" }); + expandableRowButton.focus(); + await user.keyboard("{Enter}"); expect(screen.getAllByText(/ttl:/i)).toHaveLength(2); - fireEvent.keyDown(expandableRowButton, { key: "Enter" }); + await user.keyboard("{Enter}"); await waitFor(() => { expect(screen.queryByText(/ttl:/i)).not.toBeInTheDocument(); }); }); - it("toggles an expandable audit row with Space and prevents default", async () => { + it("toggles an expandable audit row with Space", async () => { vi.spyOn(API, "getAuditLogs").mockResolvedValue({ audit_logs: [MockAuditLog], count: 1, }); + const user = userEvent.setup(); await renderPage(); const row = screen.getByTestId(`audit-log-row-${MockAuditLog.id}`); const expandableRowButton = within(row).getByRole("button"); - const spaceEvent = createEvent.keyDown(expandableRowButton, { - key: " ", - code: "Space", - }); - const preventDefaultSpy = vi.spyOn(spaceEvent, "preventDefault"); - fireEvent(expandableRowButton, spaceEvent); + expect(expandableRowButton).toHaveAttribute("role", "button"); + expect(expandableRowButton).toHaveAttribute("tabindex", "0"); + expect(expandableRowButton.tagName).toBe("DIV"); + expect(screen.queryByText(/ttl:/i)).not.toBeInTheDocument(); + + expandableRowButton.focus(); + await user.keyboard(" "); - expect(preventDefaultSpy).toHaveBeenCalled(); expect(screen.getAllByText(/ttl:/i)).toHaveLength(2); - fireEvent.keyDown(expandableRowButton, { key: " " }); + await user.keyboard(" "); await waitFor(() => { expect(screen.queryByText(/ttl:/i)).not.toBeInTheDocument(); diff --git a/site/src/pages/HealthPage/Content.tsx b/site/src/pages/HealthPage/Content.tsx index db3cdd70c5..a4a833f805 100644 --- a/site/src/pages/HealthPage/Content.tsx +++ b/site/src/pages/HealthPage/Content.tsx @@ -83,7 +83,7 @@ export const HealthyDot: FC = ({ severity }) => { export const Main: FC> = (props) => { return ( -
{ const error = createOrganizationMutation.error; return ( -
+
{ }} /> -
+
); }; diff --git a/site/src/pages/TasksPage/TasksPage.tsx b/site/src/pages/TasksPage/TasksPage.tsx index 18510fd005..e6092cdfb5 100644 --- a/site/src/pages/TasksPage/TasksPage.tsx +++ b/site/src/pages/TasksPage/TasksPage.tsx @@ -162,7 +162,7 @@ const TasksPage: FC = () => { Automate tasks with AI -
+
{ /> )} -
+
{ > }> -
+
-
+
)} diff --git a/site/src/pages/UserSettingsPage/Layout.tsx b/site/src/pages/UserSettingsPage/Layout.tsx index b953b4909e..85d9b36926 100644 --- a/site/src/pages/UserSettingsPage/Layout.tsx +++ b/site/src/pages/UserSettingsPage/Layout.tsx @@ -17,9 +17,9 @@ const Layout: FC = () => {
}> -
+
-
+
diff --git a/site/src/pages/WorkspaceSettingsPage/WorkspaceSettingsLayout.tsx b/site/src/pages/WorkspaceSettingsPage/WorkspaceSettingsLayout.tsx index 6f8a0921ef..a65883c3e9 100644 --- a/site/src/pages/WorkspaceSettingsPage/WorkspaceSettingsLayout.tsx +++ b/site/src/pages/WorkspaceSettingsPage/WorkspaceSettingsLayout.tsx @@ -73,9 +73,9 @@ export const WorkspaceSettingsLayout: FC = () => { > }> -
+
-
+
)