Skip to content

feat(ui): Make CDS screenreader accessible (WCAG 2.2 AA, zero visual change)#7787

Open
behofer wants to merge 2 commits into
ovh:masterfrom
behofer:feat/ui-screenreader-accessibility
Open

feat(ui): Make CDS screenreader accessible (WCAG 2.2 AA, zero visual change)#7787
behofer wants to merge 2 commits into
ovh:masterfrom
behofer:feat/ui-screenreader-accessibility

Conversation

@behofer

@behofer behofer commented Jul 14, 2026

Copy link
Copy Markdown

TL;DR

Large parts of CDS UI are a blackbox for a screenreader user, mainly due to unlabeled buttons, form fields and graphics, missing semantic roles (ARIA), and a workflow viewer that is fully invisible to assistive technology.
This PR fixes most of these problems with strictly zero visual change: only attributes, screenreader announcements, keyboard handling, docs and lint tooling are added. From a screenreader user's standpoint, this makes a huge(!!) difference.

How accessibility works in the UI and the rules for future template changes are documented in ui/docs/accessibility.md.

AI transparency note

The code changes in this repo were created with Claude Fable 5 model (high-effort level thinking).
I provided ideas, guidance, and proper prompting as well as some testing with NVDA screenreader.

Changes

Global

  • lang on <html>, landmark roles (banner/navigation/main), skip link (off-screen, keyboard-only), page-title announcements on navigation via CDK LiveAnnouncer
  • Toasts announced through ToastService (polite for success/info, assertive for errors); spinners/banners exposed as role="status"

Forms & names (all views)

  • nzFor + id pairing for form labels; aria-label where no visible label exists
  • Accessible names for icon-only buttons; alt fixes; status icons announce their state (aria-label="Status: …")

Interaction retrofit (attribute-only, no element swaps)

  • New appClickable directive adds role="button", tabindex="0", Enter/Space to legacy click targets (fake links, clickable divs/rows)
  • Shared tabs expose APG tab semantics (tablist/tab, aria-selected, arrow keys); data-table gains aria-sort + keyboard sorting
  • Run logs: step disclosures with aria-expanded, role="log" on streaming containers; run status changes announced

Workflow graph (libs/workflow-graph)

  • Focusable container; arrow keys move real DOM focus between nodes with announcements ("Job build, status Success, stage Build"); +/-/0 zoom/center; keyboard handling no longer intercepts arrows while typing in unrelated inputs

Tooling & docs

  • @angular-eslint/template accessibility rules enabled (warn on rules still triggered by legacy templates, error once clean)
  • ui/docs/accessibility.md — how accessibility works in the UI, the rules to follow for new/changed templates, and known limitations

Out of scope

Fixes that require visible UI changes are deliberately excluded and listed under "Known limitations" in ui/docs/accessibility.md (focus-visible styling, element swaps, graph list view, drag-and-drop keyboard alternative, CodeMirror migration). Each will come as its own PR with before/after screenshots.

Verification

  • ng build (development configuration) compiles; ng lint passes with 0 errors
  • Manual NVDA smoke pass against a local API: signin form labels, landmark/heading navigation, route announcements, toast announcements, graph keyboard navigation
  • Zero-visual-change claim: the diff contains no CSS/structure changes apart from two additive utility classes (cds-sr-only, skip link) and invisible sr-only spans

Open

I will need to test the whole screenreader accessibility in a "real" development environment. Large parts were not testable e2e locally.

Make the CDS UI perceivable and operable with screenreaders (NVDA) and
keyboard, as a strictly non-visual retrofit: default rendering is pixel
identical; only attributes, announcements and tooling change.

- document language, page-title announcements on navigation (cdk
  LiveAnnouncer), landmark roles (banner/navigation/main), skip link
- form labels programmatically associated (nzFor + ids) across all
  views; aria-label fallbacks for placeholder-only inputs
- accessible names for icon-only buttons; alt texts; status icons
  expose their state as text (aria-label "Status: ...")
- keyboard/AT retrofit for non-interactive click targets via a new
  appClickable directive (role=button, tabindex, Enter/Space)
- shared tabs expose APG tab semantics (tablist/tab, aria-selected,
  arrow-key navigation); data-table gains aria-sort + keyboard sort
- run logs: step headers as disclosures (aria-expanded), role=log on
  streaming containers; run status changes announced politely
- workflow graph (libs/workflow-graph): focusable container with
  arrow-key navigation moving real DOM focus, per-node accessible
  names, selection announcements, +/-/0 zoom keys; key handling no
  longer intercepts arrows while typing in unrelated inputs
- toasts announced via ToastService (polite/assertive); nz-spin and
  banners exposed as role=status; Monaco editors labelled
- tooling: @angular-eslint/template accessibility rules enabled as
  warnings (ratchet baseline, 0 errors); conventions documented in
  ui/docs/accessibility.md; audit and phased plan with remaining
  visual-impact items in ui/docs/accessibility-plan.md

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Benjamin Hofer <benjamin@gridscale.io>
@behofer behofer changed the title feat(ui): screenreader accessibility groundwork (WCAG 2.2 AA, zero visual change) feat(ui): Make CDS screenreader accessible (WCAG 2.2 AA, zero visual change) Jul 14, 2026
@behofer
behofer marked this pull request as ready for review July 14, 2026 11:59

@richardlt richardlt left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please rework this PR to make it easier to review, for example in the specs remove non necessary technical details and also phasing informations. In other words the spec should describe how the project is working in the commit's codebase and guideline for future changes but not the history of the project.

Replace the historical audit/phasing plan with a single spec that
describes how accessibility works in the current codebase and the
rules to follow for future template changes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@behofer

behofer commented Jul 15, 2026

Copy link
Copy Markdown
Author

It should be much cleaner now, see first comment and ui/docs/accessibility.md for the changes. For questions, let's have a chat

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants