Skip to content

Make organization switch breadcrumb trigger keyboard accessible#10501

Open
jscervantes wants to merge 1 commit into
wso2:masterfrom
jscervantes:fix/org-breadcrumb-noninteractive-tabindex
Open

Make organization switch breadcrumb trigger keyboard accessible#10501
jscervantes wants to merge 1 commit into
wso2:masterfrom
jscervantes:fix/org-breadcrumb-noninteractive-tabindex

Conversation

@jscervantes

Copy link
Copy Markdown

Purpose

Fix the jsx-a11y/no-noninteractive-tabindex accessibility warning (reported by React Doctor) on
the organization-switch breadcrumb trigger in
features/admin.organizations.v1/components/organization-switch/organization-switch-breadcrumb.tsx.

The trigger was a non-interactive <div> carrying tabIndex={ 0 } and an onClick handler, but no
interactive role and no keyboard handler. As a result it was reachable by Tab yet exposed no role
or keyboard behavior to assistive technology, and was effectively mouse-only (Enter/Space did
nothing once focused).

Rather than simply removing tabIndex, which would silence the linter but make the control
unreachable by keyboard (a regression), this PR turns the element into a legitimate dropdown
trigger:

  • role="button" so the tabIndex is justified and screen readers announce it as a control.
  • aria-haspopup="true" so assistive tech identifies it as a dropdown trigger.
  • An onKeyDown handler that activates on Enter/Space via e.currentTarget.click(), so
    keyboard activation follows the same event path as a mouse click and reaches the TenantDropdown
    that owns the real menu open/close state.

aria-expanded is intentionally omitted: the breadcrumb's local isDropDownOpen state only drives
the chevron icon and can drift from the actual TenantDropdown menu state, so binding
aria-expanded to it could announce a stale "expanded" state. This follows the existing keyboard
button pattern in features/common.workflow-approvals.v1/pages/approvals.tsx.

Note: the repo's ESLint config loads jsx-a11y but doesn't enable its rules, so pnpm lint won't flag this. Reproduced/verified by running the single rule in isolation against the file (0 warnings after the fix).

Related Issues

Related PRs

  • N/A

Checklist

  • e2e cypress tests locally verified. (for internal contributers)
  • Manual test round performed and verified.
  • UX/UI review done on the final implementation.
  • Documentation provided. (Add links if there are any)
  • Relevant backend changes deployed and verified
  • Unit tests provided. (Add links if there are any)
  • Integration tests provided. (Add links if there are any)

Security checks

Developer Checklist (Mandatory)

  • Complete the Developer Checklist in the related product-is issue to track any behavioral change or migration impact.

@CLAassistant

CLAassistant commented Jul 2, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@coderabbitai

coderabbitai Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

This PR adds keyboard accessibility to the organization-switch breadcrumb trigger by including role="button", aria-haspopup attribute, and an onKeyDown handler that activates the trigger on Enter or Space key press, along with a corresponding changeset.

Changes

Breadcrumb Accessibility Fix

Layer / File(s) Summary
Keyboard handler and ARIA attributes
features/admin.organizations.v1/components/organization-switch/organization-switch-breadcrumb.tsx, .changeset/a11y-org-breadcrumb-tabindex.md
Imports KeyboardEvent, adds role="button" and aria-haspopup="true" to the breadcrumb trigger, adds an onKeyDown handler triggering click on Enter/Space with preventDefault(), and documents the patch in a changeset.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant BreadcrumbTrigger
  User->>BreadcrumbTrigger: Press Enter/Space
  BreadcrumbTrigger->>BreadcrumbTrigger: preventDefault()
  BreadcrumbTrigger->>BreadcrumbTrigger: trigger onClick
Loading

Related Issues: Not specified in the provided context.

Related PRs: Not specified in the provided context.

Suggested labels: accessibility, a11y, patch

Suggested reviewers: Not specified in the provided context.

Poem:
A rabbit hops with keys in paw,
Tab, Enter, Space — no more a flaw,
The breadcrumb trail now speaks aloud,
"role button" whispered to the crowd,
Accessible hops, well within the law! 🐇⌨️

🚥 Pre-merge checks | ✅ 6
✅ Passed checks (6 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main change: making the organization switch breadcrumb keyboard accessible.
Description check ✅ Passed The description follows the template well, with Purpose, Related Issues, Related PRs, Checklist, Security checks, and Developer Checklist covered.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Changeset Required ✅ Passed PR changes include .changeset/a11y-org-breadcrumb-tabindex.md, a valid non-README changeset file.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • 🛠️ create changeset

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
features/admin.organizations.v1/components/organization-switch/organization-switch-breadcrumb.tsx (1)

490-516: 🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift

Split the breadcrumb trigger from the breadcrumb actions
generateBreadcrumb() renders clickable Breadcrumb.Sections and a Dropdown/Dropdown.Item inside a container with role="button" and tabIndex={ 0 }. That makes the wrapper present as a single button while still containing separate org-switch controls. Move the toggle behavior to a dedicated control or remove the outer button semantics around the interactive breadcrumb content.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@features/admin.organizations.v1/components/organization-switch/organization-switch-breadcrumb.tsx`
around lines 490 - 516, The breadcrumb trigger is currently wrapped in a single
button-like container while generateBreadcrumb() still renders its own clickable
Breadcrumb.Section and Dropdown/Dropdown.Item controls, creating nested
interactive behavior. Refactor organization-switch-breadcrumb.tsx so the outer
organization-breadcrumb wrapper no longer uses button semantics for the full
breadcrumb area; instead, move the dropdown toggle to a dedicated control or
keep the wrapper purely presentational and let generateBreadcrumb handle its own
interactions.
🧹 Nitpick comments (1)
features/admin.organizations.v1/components/organization-switch/organization-switch-breadcrumb.tsx (1)

498-503: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Minor: activation via currentTarget.click() duplicates intent instead of calling the handler directly.

Simulating a click via .click() works but couples the keyboard path to DOM click dispatch rather than invoking the shared toggle logic directly. Extracting a named handler and calling it from both onClick and onKeyDown would be more explicit and avoid relying on synthetic click semantics.

♻️ Optional refactor
+                            const toggleDropdown = (): void => setIsDropDownOpen(!isDropDownOpen);
+
                             <div
                                 role="button"
                                 aria-haspopup="true"
                                 tabIndex={ 0 }
                                 onBlur={ () => setIsDropDownOpen(false) }
                                 className="organization-breadcrumb"
-                                onClick={ () => setIsDropDownOpen(!isDropDownOpen) }
+                                onClick={ toggleDropdown }
                                 onKeyDown={ (e: KeyboardEvent<HTMLDivElement>): void => {
                                     if (e.key === "Enter" || e.key === " ") {
                                         e.preventDefault();
-                                        e.currentTarget.click();
+                                        toggleDropdown();
                                     }
                                 } }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@features/admin.organizations.v1/components/organization-switch/organization-switch-breadcrumb.tsx`
around lines 498 - 503, The keyboard activation in
organization-switch-breadcrumb currently calls e.currentTarget.click(), which
duplicates intent through DOM click dispatch instead of reusing the shared
toggle logic. Extract a named handler for the toggle action in
organization-switch-breadcrumb and invoke it from both onClick and onKeyDown,
using the existing keyboard check for Enter/Space in the onKeyDown path. Keep
the handler close to the current interactive element so the behavior stays
centralized and explicit.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In
`@features/admin.organizations.v1/components/organization-switch/organization-switch-breadcrumb.tsx`:
- Around line 490-516: The breadcrumb trigger is currently wrapped in a single
button-like container while generateBreadcrumb() still renders its own clickable
Breadcrumb.Section and Dropdown/Dropdown.Item controls, creating nested
interactive behavior. Refactor organization-switch-breadcrumb.tsx so the outer
organization-breadcrumb wrapper no longer uses button semantics for the full
breadcrumb area; instead, move the dropdown toggle to a dedicated control or
keep the wrapper purely presentational and let generateBreadcrumb handle its own
interactions.

---

Nitpick comments:
In
`@features/admin.organizations.v1/components/organization-switch/organization-switch-breadcrumb.tsx`:
- Around line 498-503: The keyboard activation in organization-switch-breadcrumb
currently calls e.currentTarget.click(), which duplicates intent through DOM
click dispatch instead of reusing the shared toggle logic. Extract a named
handler for the toggle action in organization-switch-breadcrumb and invoke it
from both onClick and onKeyDown, using the existing keyboard check for
Enter/Space in the onKeyDown path. Keep the handler close to the current
interactive element so the behavior stays centralized and explicit.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: 03306dea-f4ec-4160-8c9a-e79a6cab147a

📥 Commits

Reviewing files that changed from the base of the PR and between 910cb20 and 2023704.

📒 Files selected for processing (2)
  • .changeset/a11y-org-breadcrumb-tabindex.md
  • features/admin.organizations.v1/components/organization-switch/organization-switch-breadcrumb.tsx

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.

2 participants