Skip to content

fix(a11y): resolve ARIA violations in MCP selector and sidebar settings, add axe coverage - #14250

Open
olayinkaadelakun wants to merge 11 commits into
release-1.12.0from
LE-1992
Open

fix(a11y): resolve ARIA violations in MCP selector and sidebar settings, add axe coverage#14250
olayinkaadelakun wants to merge 11 commits into
release-1.12.0from
LE-1992

Conversation

@olayinkaadelakun

@olayinkaadelakun olayinkaadelakun commented Jul 24, 2026

Copy link
Copy Markdown
Collaborator

Summary

Accessibility (a11y) pass across the sidebar, canvas controls, app header, MCP component, node toolbar, and inspection panel. Introduces a reusable mechanism for suppressing redundant tooltip descriptions, fixes several nested-interactive-control and missing-ARIA-attribute defects, adds explicit accessible names where icon-only controls had none, and backs all of it with axe-core test coverage. Also fills in translation gaps left by the a11y work.

What changed

Core mechanism: ShadTooltip ariaDescribedBy override

shadTooltipComponent/index.tsx and types/components/index.ts add a new optional ariaDescribedBy prop. When a caller passes it explicitly (including undefined), it overrides Radix's automatic aria-describedby wiring on the tooltip trigger; when the prop is omitted entirely, Radix's default behavior is untouched. This is used at ~10 call sites in this PR to pass ariaDescribedBy={undefined} specifically where the tooltip's text just repeats the trigger's own aria-label, which previously caused screen readers to announce the same label twice. Call sites: CanvasControlButton, AppHeader (notification bell), LangflowCounts (GitHub/Discord buttons), McpComponent (refresh button), SearchConfigTrigger, SidebarHeaderComponent, SidebarSegmentedNav, ToolbarButton.

Nested-interactive-control fixes

  • DropdownControlButton.tsx: previously rendered a plain Button with a ToggleShadComponent switch nested inside it for toggle items — two independently interactive elements in one row. Replaced with Radix's real DropdownMenuItem / DropdownMenuCheckboxItem, giving toggle items the correct role="menuitemcheckbox" pattern instead of nesting a switch inside a menu item.
  • CanvasControlButton.tsx: ShadTooltip was wrapping only the icon div inside the button, not the button itself, so the tooltip trigger wasn't attached to the actual interactive element. Restructured so ShadTooltip wraps the whole ControlButton.
  • sidebarHeader.tsx: DisclosureTrigger was cloning role="button"/tabIndex=0/onClick onto a wrapper <div>, while the real settings Button sat nested inside it (axe: nested-interactive). Removed the wrapper; the toggle behavior is now wired directly onto the real button, matching the pattern in searchConfigTrigger.tsx.
  • sidebarDraggableComponent.tsx: role="button"/aria-label/tabIndex/onKeyDown were on the outer row wrapper, which also contained a real, separately-clickable "Add" button and an options menu trigger nested inside it. Moved the button role onto just the inner draggable-name element and made the Add button/options menu siblings instead of descendants; compensated the group-focusgroup-focus-within CSS so the Add button's hover/focus affordance still works.

Missing/incorrect ARIA fixes

  • mcpComponent/index.tsx: server-select button had role="combobox" without required aria-expanded/aria-controls, and no reliable accessible name (it opens a modal dialog, not a listbox, so combobox was the wrong role to begin with). Replaced with aria-haspopup="dialog" + aria-expanded + explicit aria-label for both the "select server" and "clear server" (mcp.clearServer, new key) states.
  • InspectionPanelParameterRow.tsx: "Add" button used text-muted-foreground, which fails contrast; changed to text-foreground.
  • freezeAll.jsx: removed a redundant <title>snowflake-svg</title> inside the SVG — the icon is decorative and always paired with a visible label/tooltip from its parent (ToolbarButton/ToolbarSelectItem), so the title was dead/conflicting markup, not the icon's only name source.

New explicit accessible names

  • CanvasControlsDropdown.tsx: zoom trigger now has aria-label announcing the control and current zoom percentage (canvas.zoomControlAriaLabel).
  • HelpDropdownView.tsx: help button gets an explicit aria-label (previously relied on title only).
  • editFlowSettingsComponent/index.tsx: lock-flow switch gets aria-label (flow.lockFlowAriaLabel).
  • searchInput.tsx: sidebar search input gets aria-label (sidebar.searchAriaLabel), since its placeholder text alone isn't a reliable accessible name.
  • PageComponent/index.tsx + new utils/get-node-aria-label.ts: node aria-label computation extracted to a pure, unit-tested function, and note nodes now get a fixed, non-blank label (noteNode.ariaLabel) instead of falling through to an empty display_name.

Translations

Filled in five a11y-related keys that existed only in en.json: sidebar.searchAriaLabel, canvas.zoomControlAriaLabel, flow.lockFlowAriaLabel, mcp.clearServer (missing from all 6 other locales), and noteNode.ariaLabel (missing from fr.json).

Test coverage added

New or extended axe-core coverage for: ShadTooltip, CanvasControlButton, CanvasControlsDropdown, DropdownControlButton, HelpDropdown, InspectionPanelParameterRow, McpComponent, LangflowCounts, AppHeader (+ dedicated unmocked notification-dropdown suite), SearchConfigTrigger, SidebarHeaderComponent, SidebarSegmentedNav, EditFlowSettings, ToolbarButton, SearchInput, SidebarDraggableComponent, getNodeAriaLabel. Several are new *.a11y.test.tsx files rendering real, unmocked components — existing suites mocked away the exact Button/ShadTooltip/Radix primitives whose attributes needed verifying.

Also fixed a test-mock bug in Dropdowns.test.tsx: the flowStore mock ignored the Zustand selector argument, producing a bogus aria-checked="[object Object]" that masked what axe should have caught. Fixed the mock and added correct ARIA roles (menu/menuitem/separator) to the mocked dropdown primitives.

Known issues, not fixed (flagged for follow-up)

  • appHeaderComponent/index.tsx: a redundant AlertDropdown nested inside another AlertDropdown around the notification bell. Confirmed via test to be dead code (the outer Popover trigger never receives clicks — ShadTooltip silently drops the cloned onClick), not a duplicate-render bug; axe passes on it. Recommend a small cleanup ticket.
  • DropdownControlButton.tsx's move to a real Radix DropdownMenuItem means the canvas zoom dropdown now closes on every click of Zoom In/Out/Reset/Fit View (Radix auto-closes on item select by default). The toggle branch already prevents this (onSelect guard); the plain-item branch does not. Previously, as a plain Button, the menu likely stayed open across repeated clicks. Needs a product call on whether that's desired.
  • sidebar.addComponentToCanvas was removed from en.json on this branch but still lingers, unused, in the other 6 locale files. Harmless, but worth cleaning up.

QE / How to validate

Manual — tooltip double-announcement fix

  1. Turn on a screen reader (VoiceOver on Mac: Cmd+F5).
  2. Tab to any icon-only button with a tooltip (canvas zoom controls, sidebar nav icons, node toolbar buttons, app header GitHub/Discord/notification icons, MCP refresh button).
  3. Confirm the label is announced once, not twice.

Manual — MCP server selector

  1. Open a flow, add an MCP component to the canvas, open the node.
  2. With the screen reader on, Tab to the server-select control.
  3. Confirm it announces as a button with a clear name (loading state / selected server name / "Select a server"), not an unlabeled or malformed control.
  4. Select a server, then confirm the same control now offers a distinctly-labeled "Clear selected server" action.

Manual — Sidebar settings toggle (legacy sidebar)

  1. Enable the legacy sidebar and Tab through the sidebar header.
  2. Confirm there is exactly one stop for the settings (sliders) button — previously there were two (an unlabeled outer stop, then the real button).
  3. Press Enter/Space on it; confirm the beta/legacy toggles panel opens and closes correctly.

Manual — Sidebar draggable component row

  1. In the component sidebar, Tab to a component row.
  2. Confirm Tab stops land on: the draggable name (announced with "add to canvas" label), then the visible "Add" button, then the options menu — three distinct, correctly-labeled stops, not overlapping/nested ones.

Manual — Canvas zoom dropdown (known behavior change)

  1. Open the canvas zoom dropdown.
  2. Click "Zoom In." Confirm whether the menu closing after each click is acceptable, or flag if it should stay open for repeated clicks.

Manual — Translations

  1. Switch the app language to each of de/es/fr/ja/pt/zh-Hans.
  2. Confirm no raw i18n keys (e.g. mcp.clearServer, flow.lockFlowAriaLabel) are ever visible or announced — everything should show translated text.

Testing performed

  • Full frontend Jest suite: 487 suites / 5527 tests passing
  • tsc --noEmit: no new errors in touched files
  • Each axe violation manually triaged to confirm real DOM/ARIA defect vs. test-mock artifact before fixing

Summary by CodeRabbit

  • Accessibility Improvements

    • Improved accessible labels and keyboard support across toolbars, canvas controls, sidebars, flow nodes, MCP controls, and lock settings.
    • Added clearer screen-reader announcements for zoom levels, searches, notes, settings, notifications, and actions.
    • Improved tooltip behavior to prevent redundant descriptions.
    • Enhanced dropdown semantics, focus management, and keyboard interactions.
    • Improved contrast for parameter actions.
  • Bug Fixes

    • Prevented duplicate notification popovers.
    • Corrected accessible labeling for flow nodes, including note nodes and unnamed nodes.
  • Tests

    • Added extensive automated accessibility coverage across headers, tooltips, dropdowns, sidebars, settings, and flow controls.

Olayinka Adelakun and others added 5 commits July 22, 2026 14:38
…ers, sidebar list nesting, beta/legacy switch labels)

Brings in e4f0d5a and e9342a6, which fix the same button-name/aria-allowed-attr/list-nesting issues that a fresh scan showed as still-open on this branch — those commits existed on a sibling branch that hadn't been merged here yet.
@coderabbitai

coderabbitai Bot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 166a8849-1138-4580-909a-c01df8126aed

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Walkthrough

This PR adds accessibility improvements across the Flow UI: ShadTooltip supports an ariaDescribedBy override, interactive controls (header, canvas, sidebar, MCP, toolbar) gain ARIA labels and keyboard semantics, a getNodeAriaLabel helper centralizes node labeling, new locale strings are added across languages, and extensive axe-based accessibility tests are introduced.

Changes

Frontend accessibility updates

Layer / File(s) Summary
Tooltip ARIA contract
types/components/index.ts, components/common/shadTooltipComponent/index.tsx, components/common/shadTooltipComponent/__tests__/*
ShadToolTipType gains an optional ariaDescribedBy prop; ShadTooltip conditionally sets aria-describedby on TooltipTrigger, validated by new suppression/custom/default test cases.
Header and canvas control semantics
components/core/appHeaderComponent/..., components/core/canvasControlsComponent/...
Notification, GitHub/Discord, zoom dropdown, help, and dropdown menu items get accessible labels, Radix menu roles, ariaDescribedBy={undefined} tooltip wiring, and matching axe/role tests.
Sidebar control accessibility
pages/FlowPage/components/flowSidebarComponent/components/...
Search input, settings trigger, segmented nav, and draggable component rows gain aria-labels, keyboard Enter/Space activation, aria-expanded/role attributes, and axe/keyboard tests.
Component control semantics
components/core/editFlowSettingsComponent/..., components/core/parameterRenderComponent/components/mcpComponent/..., pages/FlowPage/components/InspectionPanel/..., pages/FlowPage/components/nodeToolbarComponent/..., icons/freezeAll/freezeAll.jsx
Lock switch, MCP dropdown/refresh, inspection-panel Add button styling, and toolbar tooltip get ARIA attributes, contrast fixes, and ariaDescribedBy suppression, with corresponding tests.
Node labels and localization
pages/FlowPage/components/PageComponent/..., locales/*.json
getNodeAriaLabel centralizes node aria-label generation with note-node special-casing, and new ARIA/label translation keys are added across all locale files.

Estimated code review effort: 3 (Moderate) | ~30 minutes

Suggested labels: test

Suggested reviewers: cristhianzl, viktoravelino, deon-sanchez

🚥 Pre-merge checks | ✅ 4 | ❌ 5

❌ Failed checks (1 warning, 4 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 16.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Test Coverage For New Implementations ❓ Inconclusive Repository clone failed, so this custom check could not run with code access. Retry the review run. If this persists, inspect pre-merge custom-check logs for infrastructure or agent runtime failures.
Test Quality And Coverage ❓ Inconclusive Repository clone failed, so this custom check could not run with code access. Retry the review run. If this persists, inspect pre-merge custom-check logs for infrastructure or agent runtime failures.
Test File Naming And Structure ❓ Inconclusive Repository clone failed, so this custom check could not run with code access. Retry the review run. If this persists, inspect pre-merge custom-check logs for infrastructure or agent runtime failures.
Excessive Mock Usage Warning ❓ Inconclusive Repository clone failed, so this custom check could not run with code access. Retry the review run. If this persists, inspect pre-merge custom-check logs for infrastructure or agent runtime failures.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is relevant and specific to the PR’s main a11y work, though it only mentions two of several affected areas.
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.
✨ Finishing Touches 💡 2
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🛠️ Fix failing CI checks 💡
  • Fix failing CI checks
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch LE-1992

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.

@github-actions github-actions Bot added the bug Something isn't working label Jul 24, 2026
@github-actions

Copy link
Copy Markdown
Contributor

✅ Test Coverage Advisor

No source changes detected without accompanying tests. Thanks for keeping coverage up! 🎉

Advisory check only — never blocks merge.

@github-actions github-actions Bot added bug Something isn't working and removed bug Something isn't working labels Jul 24, 2026
@github-actions

github-actions Bot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Frontend Unit Test Coverage Report

Coverage Summary

Lines Statements Branches Functions
Coverage: 48%
48.75% (69843/143247) 70.01% (9772/13958) 46.55% (1613/3465)

Unit Test Results

Tests Skipped Failures Errors Time
5484 0 💤 0 ❌ 0 🔥 20m 12s ⏱️

@github-actions github-actions Bot added the lgtm This PR has been approved by a maintainer label Jul 28, 2026
@codecov

codecov Bot commented Jul 28, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 61.29%. Comparing base (f8c5f9c) to head (4c1fe73).
⚠️ Report is 103 commits behind head on release-1.12.0.

Additional details and impacted files

Impacted file tree graph

@@                Coverage Diff                 @@
##           release-1.12.0   #14250      +/-   ##
==================================================
- Coverage           61.30%   61.29%   -0.02%     
==================================================
  Files                2342     2342              
  Lines              237114   236781     -333     
  Branches            33340    33280      -60     
==================================================
- Hits               145354   145124     -230     
+ Misses              89963    89860     -103     
  Partials             1797     1797              
Files with missing lines Coverage Δ
...s/GenericNode/components/NodeOutputfield/index.tsx 37.82% <ø> (-0.79%) ⬇️
...mNodes/GenericNode/components/NodeStatus/index.tsx 34.62% <ø> (ø)
src/frontend/src/CustomNodes/NoteNode/index.tsx 90.80% <ø> (-0.11%) ⬇️
...c/components/common/shadTooltipComponent/index.tsx 35.84% <ø> (-0.69%) ⬇️
.../appHeaderComponent/components/langflow-counts.tsx 29.21% <ø> (ø)
...d/src/components/core/appHeaderComponent/index.tsx 35.76% <ø> (+0.23%) ⬆️
...re/canvasControlsComponent/CanvasControlButton.tsx 92.15% <ø> (-1.40%) ⬇️
...canvasControlsComponent/CanvasControlsDropdown.tsx 97.75% <ø> (ø)
.../canvasControlsComponent/DropdownControlButton.tsx 89.13% <ø> (-5.67%) ⬇️
.../core/canvasControlsComponent/HelpDropdownView.tsx 96.52% <ø> (ø)
... and 18 more
🚀 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.

Base automatically changed from LE-1986 to release-1.12.0 July 29, 2026 17:51
@github-actions github-actions Bot added bug Something isn't working and removed bug Something isn't working labels Jul 29, 2026
@github-actions github-actions Bot added bug Something isn't working and removed bug Something isn't working labels Jul 30, 2026
@github-actions github-actions Bot added bug Something isn't working and removed bug Something isn't working labels Jul 30, 2026
…e button, refresh flowSettingsModal a11y tests
@github-actions github-actions Bot added bug Something isn't working and removed bug Something isn't working labels Jul 30, 2026
@github-actions github-actions Bot added bug Something isn't working and removed bug Something isn't working labels Jul 30, 2026

@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.

Actionable comments posted: 1

🧹 Nitpick comments (3)
src/frontend/src/components/core/canvasControlsComponent/__tests__/Dropdowns.test.tsx (1)

3-3: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Axe check validates the mocked ARIA roles, not real Radix accessibility output.

@/components/ui/dropdown-menu is fully mocked here with hand-authored role="menu"/role="menuitem"/role="menuitemcheckbox" attributes, then the new should_have_no_axe_violations test runs axe against HelpDropdown built on this mock. This mostly proves the mock's own roles are internally consistent rather than exercising the real Radix DropdownMenu DOM/ARIA output that ships to users — DropdownControlButton.test.tsx and CanvasControlsDropdown.test.tsx mount the real Radix primitives for their equivalent axe checks, which gives genuine confidence. As per coding guidelines, "prefer integration tests when unit tests are overly mocked" — consider dropping the dropdown-menu mock (or scoping the axe test to real primitives) so this check reflects actual runtime accessibility.

Also applies to: 24-52, 116-124

🤖 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
`@src/frontend/src/components/core/canvasControlsComponent/__tests__/Dropdowns.test.tsx`
at line 3, Update the axe accessibility test for HelpDropdown to exercise the
real Radix dropdown-menu primitives instead of the hand-authored mock roles.
Remove or scope the `@/components/ui/dropdown-menu` mock while preserving the
existing HelpDropdown behavior and assertions, matching the real-primitive
approach used by DropdownControlButton.test.tsx and
CanvasControlsDropdown.test.tsx.

Source: Coding guidelines

src/frontend/src/components/core/parameterRenderComponent/components/mcpComponent/__tests__/McpComponent.test.tsx (1)

148-163: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Prefer rerender over a second unmounted render call.

This test renders McpComponent twice without unmounting the first instance, leaving two live DOM trees; getAllByTestId(...)[1] then relies on insertion order to pick out the second instance's button. Using the rerender function returned by the first render() call would swap props on the same instance and make the "distinctly named in each state" intent explicit, without depending on cross-tree DOM ordering.

♻️ Proposed refactor
-    render(<McpComponent {...defaultProps()} />);
-    expect(screen.getByTestId("mcp-server-dropdown")).toHaveAccessibleName(
-      "broken-server",
-    );
-
-    render(
-      <McpComponent
-        {...defaultProps()}
-        value={{ name: "", config: { command: "test" } }}
-      />,
-    );
-    expect(
-      screen.getAllByTestId("mcp-server-dropdown")[1],
-    ).toHaveAccessibleName("Clear selected server");
+    const { rerender } = render(<McpComponent {...defaultProps()} />);
+    expect(screen.getByTestId("mcp-server-dropdown")).toHaveAccessibleName(
+      "broken-server",
+    );
+
+    rerender(
+      <McpComponent
+        {...defaultProps()}
+        value={{ name: "", config: { command: "test" } }}
+      />,
+    );
+    expect(screen.getByTestId("mcp-server-dropdown")).toHaveAccessibleName(
+      "Clear selected server",
+    );
🤖 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
`@src/frontend/src/components/core/parameterRenderComponent/components/mcpComponent/__tests__/McpComponent.test.tsx`
around lines 148 - 163, Update the test using the render result’s rerender
function instead of calling render a second time. Reuse the same
mcp-server-dropdown query after changing props so assertions target the single
McpComponent instance and no longer depend on getAllByTestId insertion order.
src/frontend/src/pages/FlowPage/components/flowSidebarComponent/components/__tests__/sidebarDraggableComponent.test.tsx (1)

194-203: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Axe test is validated mostly against hand-authored mocks, not real components.

ShadTooltip, Button, and the entire select-custom module (Select, SelectTrigger, SelectContent, SelectItem) are all replaced by simplified stand-ins here — the SelectTrigger mock even hardcodes aria-expanded={false} regardless of actual state. The new should_have_no_axe_violations test (Lines 271-279) therefore asserts mostly against markup this test file itself authored, not the real Radix/Button/ShadTooltip output, so it offers limited protection against real a11y regressions in those primitives.

Compare with sidebarHeader.a11y.test.tsx in this same PR, which deliberately keeps Button/ShadTooltip/sidebar primitives unmocked specifically to exercise real ARIA output, while only mocking child sections that have their own dedicated a11y coverage. Consider a similar unmocked a11y suite here (or narrowing which pieces are mocked) for a more meaningful signal.

As per coding guidelines: "Warn when frontend test files rely on excessive mocks that obscure what is actually being tested, replace mocks with real objects or test doubles when mocks become excessive, and prefer integration tests when unit tests are overly mocked."

Also applies to: 271-279

🤖 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
`@src/frontend/src/pages/FlowPage/components/flowSidebarComponent/components/__tests__/sidebarDraggableComponent.test.tsx`
around lines 194 - 203, The accessibility test relies on mocked ShadTooltip,
Button, and select-custom primitives, so it validates authored stand-ins rather
than real ARIA behavior. Update the suite around should_have_no_axe_violations
to remove those primitive mocks, or narrow mocking to child sections with
dedicated coverage, while retaining real Select, SelectTrigger, SelectContent,
SelectItem, Button, and ShadTooltip implementations. Ensure the SelectTrigger
uses its actual aria-expanded state.

Source: Coding guidelines

🤖 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.

Inline comments:
In
`@src/frontend/src/pages/FlowPage/components/flowSidebarComponent/components/sidebarDraggableComponent.tsx`:
- Around line 107-114: Update handleKeyDown and the role="button" element in
sidebarDraggableComponent so disabled items cannot be activated by keyboard:
guard addComponent with the same disabled check used by onDoubleClick, and
remove disabled items from the tab order while keeping enabled items focusable.

---

Nitpick comments:
In
`@src/frontend/src/components/core/canvasControlsComponent/__tests__/Dropdowns.test.tsx`:
- Line 3: Update the axe accessibility test for HelpDropdown to exercise the
real Radix dropdown-menu primitives instead of the hand-authored mock roles.
Remove or scope the `@/components/ui/dropdown-menu` mock while preserving the
existing HelpDropdown behavior and assertions, matching the real-primitive
approach used by DropdownControlButton.test.tsx and
CanvasControlsDropdown.test.tsx.

In
`@src/frontend/src/components/core/parameterRenderComponent/components/mcpComponent/__tests__/McpComponent.test.tsx`:
- Around line 148-163: Update the test using the render result’s rerender
function instead of calling render a second time. Reuse the same
mcp-server-dropdown query after changing props so assertions target the single
McpComponent instance and no longer depend on getAllByTestId insertion order.

In
`@src/frontend/src/pages/FlowPage/components/flowSidebarComponent/components/__tests__/sidebarDraggableComponent.test.tsx`:
- Around line 194-203: The accessibility test relies on mocked ShadTooltip,
Button, and select-custom primitives, so it validates authored stand-ins rather
than real ARIA behavior. Update the suite around should_have_no_axe_violations
to remove those primitive mocks, or narrow mocking to child sections with
dedicated coverage, while retaining real Select, SelectTrigger, SelectContent,
SelectItem, Button, and ShadTooltip implementations. Ensure the SelectTrigger
uses its actual aria-expanded state.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: b3a8846e-5636-4cd0-8135-ea18f1445ddf

📥 Commits

Reviewing files that changed from the base of the PR and between 9c653d2 and 08c908f.

📒 Files selected for processing (47)
  • src/frontend/src/components/common/shadTooltipComponent/__tests__/shadTooltip.a11y.test.tsx
  • src/frontend/src/components/common/shadTooltipComponent/__tests__/shadTooltip.test.tsx
  • src/frontend/src/components/common/shadTooltipComponent/index.tsx
  • src/frontend/src/components/core/appHeaderComponent/__tests__/appHeader.a11y.test.tsx
  • src/frontend/src/components/core/appHeaderComponent/__tests__/appHeader.notificationDropdown.test.tsx
  • src/frontend/src/components/core/appHeaderComponent/components/__tests__/langflow-counts.test.tsx
  • src/frontend/src/components/core/appHeaderComponent/components/langflow-counts.tsx
  • src/frontend/src/components/core/appHeaderComponent/index.tsx
  • src/frontend/src/components/core/canvasControlsComponent/CanvasControlButton.tsx
  • src/frontend/src/components/core/canvasControlsComponent/CanvasControlsDropdown.tsx
  • src/frontend/src/components/core/canvasControlsComponent/DropdownControlButton.tsx
  • src/frontend/src/components/core/canvasControlsComponent/HelpDropdownView.tsx
  • src/frontend/src/components/core/canvasControlsComponent/__tests__/CanvasControlButton.test.tsx
  • src/frontend/src/components/core/canvasControlsComponent/__tests__/CanvasControlsDropdown.test.tsx
  • src/frontend/src/components/core/canvasControlsComponent/__tests__/DropdownControlButton.test.tsx
  • src/frontend/src/components/core/canvasControlsComponent/__tests__/Dropdowns.test.tsx
  • src/frontend/src/components/core/editFlowSettingsComponent/__tests__/editFlowSettingsComponent.test.tsx
  • src/frontend/src/components/core/editFlowSettingsComponent/index.tsx
  • src/frontend/src/components/core/parameterRenderComponent/components/mcpComponent/__tests__/McpComponent.test.tsx
  • src/frontend/src/components/core/parameterRenderComponent/components/mcpComponent/index.tsx
  • src/frontend/src/icons/freezeAll/freezeAll.jsx
  • src/frontend/src/locales/de.json
  • src/frontend/src/locales/en.json
  • src/frontend/src/locales/es.json
  • src/frontend/src/locales/fr.json
  • src/frontend/src/locales/ja.json
  • src/frontend/src/locales/pt.json
  • src/frontend/src/locales/zh-Hans.json
  • src/frontend/src/pages/FlowPage/components/InspectionPanel/__tests__/InspectionPanelParameterRow.test.tsx
  • src/frontend/src/pages/FlowPage/components/InspectionPanel/components/InspectionPanelParameterRow.tsx
  • src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx
  • src/frontend/src/pages/FlowPage/components/PageComponent/utils/__tests__/get-node-aria-label.test.ts
  • src/frontend/src/pages/FlowPage/components/PageComponent/utils/get-node-aria-label.ts
  • src/frontend/src/pages/FlowPage/components/flowSidebarComponent/components/__tests__/searchConfigTrigger.a11y.test.tsx
  • src/frontend/src/pages/FlowPage/components/flowSidebarComponent/components/__tests__/searchInput.test.tsx
  • src/frontend/src/pages/FlowPage/components/flowSidebarComponent/components/__tests__/sidebarDraggableComponent.test.tsx
  • src/frontend/src/pages/FlowPage/components/flowSidebarComponent/components/__tests__/sidebarHeader.a11y.test.tsx
  • src/frontend/src/pages/FlowPage/components/flowSidebarComponent/components/__tests__/sidebarHeader.test.tsx
  • src/frontend/src/pages/FlowPage/components/flowSidebarComponent/components/__tests__/sidebarSegmentedNav.a11y.test.tsx
  • src/frontend/src/pages/FlowPage/components/flowSidebarComponent/components/searchConfigTrigger.tsx
  • src/frontend/src/pages/FlowPage/components/flowSidebarComponent/components/searchInput.tsx
  • src/frontend/src/pages/FlowPage/components/flowSidebarComponent/components/sidebarDraggableComponent.tsx
  • src/frontend/src/pages/FlowPage/components/flowSidebarComponent/components/sidebarHeader.tsx
  • src/frontend/src/pages/FlowPage/components/flowSidebarComponent/components/sidebarSegmentedNav.tsx
  • src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/components/__tests__/toolbar-button.test.tsx
  • src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/components/toolbar-button.tsx
  • src/frontend/src/types/components/index.ts
💤 Files with no reviewable changes (2)
  • src/frontend/src/icons/freezeAll/freezeAll.jsx
  • src/frontend/src/pages/FlowPage/components/flowSidebarComponent/components/tests/sidebarHeader.test.tsx

Comment on lines +107 to +114
const handleKeyDown = (e) => {
if (e.key === "Enter" || e.key === " ") {
e.preventDefault();
e.stopPropagation();
addComponent(apiClass, itemName);
}
};

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.

🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win

Keyboard Enter/Space bypasses the disabled guard that onDoubleClick enforces.

handleKeyDown calls addComponent(apiClass, itemName) unconditionally on Enter/Space, but the sibling onDoubleClick handler explicitly checks if (!disabled) before doing the same. Since the role="button" div keeps tabIndex={0} even when disabled is true, a keyboard user can still Tab to it and press Enter/Space to add a component that is supposed to be blocked (mouse users are blocked via pointer-events-none on the wrapper, but that CSS property has no effect on keyboard-dispatched events).

🐛 Proposed fix
     const handleKeyDown = (e) => {
-      if (e.key === "Enter" || e.key === " ") {
+      if (!disabled && (e.key === "Enter" || e.key === " ")) {
         e.preventDefault();
         e.stopPropagation();
         addComponent(apiClass, itemName);
       }
     };

and, for defense in depth, remove the element from the tab order too:

-              tabIndex={0}
+              tabIndex={disabled ? -1 : 0}

Also applies to: 143-152

🤖 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
`@src/frontend/src/pages/FlowPage/components/flowSidebarComponent/components/sidebarDraggableComponent.tsx`
around lines 107 - 114, Update handleKeyDown and the role="button" element in
sidebarDraggableComponent so disabled items cannot be activated by keyboard:
guard addComponent with the same disabled check used by onDoubleClick, and
remove disabled items from the tab order while keeping enabled items focusable.

@github-actions github-actions Bot added bug Something isn't working and removed bug Something isn't working labels Jul 30, 2026
@github-actions github-actions Bot added bug Something isn't working and removed bug Something isn't working labels Jul 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working lgtm This PR has been approved by a maintainer

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants