Skip to content

fix(a11y): fix invalid list structures in navigation and alert group (WCAG 1.3.1)#1564

Merged
olexii4 merged 1 commit into
mainfrom
CRW-10232
May 13, 2026
Merged

fix(a11y): fix invalid list structures in navigation and alert group (WCAG 1.3.1)#1564
olexii4 merged 1 commit into
mainfrom
CRW-10232

Conversation

@olexii4
Copy link
Copy Markdown
Contributor

@olexii4 olexii4 commented May 12, 2026

What does this PR do?

Fixes two violations of WCAG 2.2 criterion 1.3.1 Info and Relationships (Level A).

WCAG 1.3.1 requires that information conveyed through visual presentation (including list structure) is also available programmatically. When <ul> or <ol> elements contain children that are not <li>, <script>, or <template>, screen readers cannot correctly announce list context or item count, breaking the programmatic relationship for assistive technology users.

Fix 1 — Navigation sidebar: NavGroup nested inside NavList

File: src/Layout/Navigation/RecentList.tsx

The "Recent Workspaces" section wrapped a NavGroup (which PatternFly renders as <section class="pf-v6-c-nav__section">) inside a NavList (which renders as <ul class="pf-v6-c-nav__list" role="list">). This produced the invalid structure:

<!-- Before (invalid) -->
<ul class="pf-v6-c-nav__list" role="list">
  <section class="pf-v6-c-nav__section">  <!-- <section> not allowed directly in <ul> -->
    <ul>
      <li>...</li>
    </ul>
  </section>
</ul>

NavGroup already creates its own internal <ul> for its NavItem children — the outer NavList wrapper was redundant and structurally invalid.

Fix: remove the NavList wrapper from NavigationRecentList. NavGroup now sits directly inside the Nav element alongside NavigationMainList, producing valid HTML:

<!-- After (valid) -->
<nav aria-label="Navigation">
  <ul class="pf-v6-c-nav__list">       <!-- NavigationMainList -->
    <li>Create Workspace</li>
    <li>Workspaces (N)</li>
  </ul>
  <section class="pf-v6-c-nav__section">  <!-- NavigationRecentList (NavGroup) -->
    <h2>RECENT WORKSPACES</h2>
    <ul>
      <li>workspace-name</li>
    </ul>
  </section>
</nav>
-import { NavGroup, NavList } from '@patternfly/react-core';
+import { NavGroup } from '@patternfly/react-core';

-  return (
-    <NavList>
-      <NavGroup title="RECENT WORKSPACES" style={{ marginTop: '25px' }}>
-        {recentWorkspaceItems}
-      </NavGroup>
-    </NavList>
-  );
+  return (
+    <NavGroup title="RECENT WORKSPACES" style={{ marginTop: '25px' }}>
+      {recentWorkspaceItems}
+    </NavGroup>
+  );

Fix 2 — Toast alert group: empty <ul role="list">

File: src/components/AppAlertGroup/index.tsx

AppAlertGroup unconditionally rendered <AlertGroup isToast>, which PatternFly renders as <ul role="list" class="pf-v6-c-alert-group pf-m-toast">. When there are no active alerts the list is empty — a role="list" element with no role="listitem" children violates 1.3.1.

Fix: return an empty fragment when there are no alerts (consistent with the existing guard in WorkspaceProgress/Alert/index.tsx):

 public render(): React.ReactElement {
-  return <AlertGroup isToast>{this.state.alerts.map(alert => this.getAlert(alert))}</AlertGroup>;
+  const { alerts } = this.state;
+  if (alerts.length === 0) {
+    return <></>;
+  }
+  return <AlertGroup isToast>{alerts.map(alert => this.getAlert(alert))}</AlertGroup>;
 }

Screenshot/screencast of this PR

Знімок екрана 2026-05-13 о 00 04 31

What issues does this PR fix or reference?

fixes https://redhat.atlassian.net/browse/CRW-10232

Is it tested? How?

  • Verified with browser DevTools Accessibility panel that <ul> elements contain only valid <li> children.
  • Manually verified with macOS VoiceOver on Chrome that the navigation sidebar now announces correct list structure and item count.

Release Notes

Docs PR

…(WCAG 1.3.1)

WCAG 2.2 criterion 1.3.1 (Info and Relationships, Level A) requires that
programmatic structure matches the visual presentation so assistive
technologies can correctly expose list context and item counts.

Two violations fixed:

1. Navigation sidebar (RecentList): NavGroup (renders <section>) was a direct
   child of NavList (renders <ul>), producing <ul><section>...</section></ul>.
   HTML forbids <section> as a direct child of <ul>; screen readers could not
   announce the correct list context or item count.

   Fix: remove the NavList wrapper from NavigationRecentList. NavGroup already
   creates its own internal <ul> for its NavItem children, so the rendered
   structure is now <nav><ul>...</ul><section><ul><li>...</li></ul></section></nav>,
   which is valid and correctly exposes the list to assistive technologies.

2. Toast alert group (AppAlertGroup): AlertGroup with isToast always rendered
   <ul role="list" class="pf-v6-c-alert-group pf-m-toast"> even when empty.
   An empty element declared as a list violates 1.3.1 because it claims a list
   relationship with no list items.

   Fix: return an empty fragment when there are no alerts, consistent with the
   existing guard in WorkspaceProgress/Alert.

Assisted-by: Claude Sonnet 4.6
Signed-off-by: Oleksii Orel <oorel@redhat.com>
@olexii4 olexii4 requested review from akurinnoy and ibuziuk as code owners May 12, 2026 14:38
@che-bot
Copy link
Copy Markdown
Contributor

che-bot commented May 12, 2026

Click here to review and test in web IDE: Contribute

@github-actions
Copy link
Copy Markdown

Docker image build succeeded: quay.io/eclipse/che-dashboard:pr-1564 (linux/amd64, linux/arm64)

kubectl patch command
kubectl patch -n eclipse-che "checluster/eclipse-che" --type=json -p="[{"op": "replace", "path": "/spec/components/dashboard/deployment", "value": {containers: [{image: "quay.io/eclipse/che-dashboard:pr-1564", name: che-dashboard}]}}]"

@olexii4 olexii4 requested a review from dmytro-ndp May 12, 2026 21:00
@svor
Copy link
Copy Markdown
Contributor

svor commented May 13, 2026

/retest

Copy link
Copy Markdown
Contributor

@svor svor left a comment

Choose a reason for hiding this comment

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

lgtm

@codecov
Copy link
Copy Markdown

codecov Bot commented May 13, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 92.51%. Comparing base (7395441) to head (f908782).

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #1564   +/-   ##
=======================================
  Coverage   92.50%   92.51%           
=======================================
  Files         561      561           
  Lines       55890    55892    +2     
  Branches     4219     4223    +4     
=======================================
+ Hits        51700    51706    +6     
+ Misses       4142     4138    -4     
  Partials       48       48           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Copy Markdown
Contributor

@dmytro-ndp dmytro-ndp left a comment

Choose a reason for hiding this comment

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

@olexii4 : I tested Eclipse Che Next with the User Dashboard image quay.io/eclipse/che-dashboard:pr-1564, and there was correct HTML sctructure:

  1. Left sidebar menu and page navigation (html elements .pf-v6-c-nav__list) lists had the correct structure <ul><li>...:
Image
  1. There were no <ul> elements defined as a ‘list' that didn’t contain child elements.

@openshift-ci
Copy link
Copy Markdown

openshift-ci Bot commented May 13, 2026

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: dmytro-ndp, olexii4, svor

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@olexii4 olexii4 merged commit 94fe6ea into main May 13, 2026
19 checks passed
@olexii4 olexii4 deleted the CRW-10232 branch May 13, 2026 19:53
svor added a commit that referenced this pull request May 14, 2026
* fix(a11y): fix invalid list structures in navigation and alert group (WCAG 1.3.1) (#1564)

WCAG 2.2 criterion 1.3.1 (Info and Relationships, Level A) requires that
programmatic structure matches the visual presentation so assistive
technologies can correctly expose list context and item counts.

Two violations fixed:

1. Navigation sidebar (RecentList): NavGroup (renders <section>) was a direct
   child of NavList (renders <ul>), producing <ul><section>...</section></ul>.
   HTML forbids <section> as a direct child of <ul>; screen readers could not
   announce the correct list context or item count.

   Fix: remove the NavList wrapper from NavigationRecentList. NavGroup already
   creates its own internal <ul> for its NavItem children, so the rendered
   structure is now <nav><ul>...</ul><section><ul><li>...</li></ul></section></nav>,
   which is valid and correctly exposes the list to assistive technologies.

2. Toast alert group (AppAlertGroup): AlertGroup with isToast always rendered
   <ul role="list" class="pf-v6-c-alert-group pf-m-toast"> even when empty.
   An empty element declared as a list violates 1.3.1 because it claims a list
   relationship with no list items.

   Fix: return an empty fragment when there are no alerts, consistent with the
   existing guard in WorkspaceProgress/Alert.

Assisted-by: Claude Sonnet 4.6

Signed-off-by: Oleksii Orel <oorel@redhat.com>

* fix(a11y): add role="img" to workspace status indicator span (WCAG 4.1.2) (#1563)

WCAG 2.2 criterion 4.1.2 (Name, Role, Value, Level A) requires that elements
with aria-label have a valid semantic role so assistive technologies can
correctly expose the value.

The workspace status indicator used a generic <span> with aria-label but no
role, causing screen readers to silently ignore the status text. The same span
is used in the Workspaces list and the Workspace Details Overview.

Adding role="img" to the span declares it as a named graphic element.
Screen readers now announce e.g. "Workspace status is Running" when the
element receives focus, satisfying the criterion.

Assisted-by: Claude Sonnet 4.6

Signed-off-by: Oleksii Orel <oorel@redhat.com>

---------

Signed-off-by: Oleksii Orel <oorel@redhat.com>
Co-authored-by: Oleksii Orel <oorel@redhat.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants