Skip to content

Fix Resources accessibility keyboard and reflow paths#17926

Open
adamint wants to merge 16 commits into
microsoft:mainfrom
adamint:adamint/a11y-resources-keyboard-focus
Open

Fix Resources accessibility keyboard and reflow paths#17926
adamint wants to merge 16 commits into
microsoft:mainfrom
adamint:adamint/a11y-resources-keyboard-focus

Conversation

@adamint
Copy link
Copy Markdown
Member

@adamint adamint commented Jun 4, 2026

Description

Fixes #17466
Fixes #17656
Fixes #17651
Fixes #17654
Fixes #17469

Condenses the Resources-page accessibility fixes into one related PR. This keeps the keyboard/menu work together: View options now announces expanded/collapsed state, restores focus after item selection, nested row controls no longer also activate the parent row, narrow Resources tabs stay visible, and popup Tab navigation no longer falls back to the first page control.

Supersedes the smaller draft PRs #17774, #17776, #17789, #17791, and #17793.

User-facing usage

Keyboard and screen reader users get predictable Resources-page navigation:

View options closed: aria-expanded="false"
View options open:   aria-expanded="true"
After menu item selection: focus returns to View options
Enter on "Open in text visualizer": opens only the text visualizer, not row details too
320px Resources tabs: Resources, Parameters, and Graph remain visible
Tab out of View options popup: focus moves to Resources instead of Aspire

Preserved scenarios and proof

Issue Scenario Proof
#17466 View options exposes reliable expanded/collapsed state. Source PR #17774. Artifact folder: https://github.com/adamint/aspire/tree/a11y-artifacts-20260601042635/17466. Visual proof: https://raw.githubusercontent.com/adamint/aspire/c39fcb45309be7a7cf64777cebc78fa0ca482095/proof/a11y/17774/pr-17774-visual-proof.mp4
#17656 Selecting Collapse child resources returns focus to the View options trigger. Source PR #17776. Artifact folder: https://github.com/adamint/aspire/tree/a11y-artifacts-20260601042635/17656. Visual proof: https://raw.githubusercontent.com/adamint/aspire/cd33e79ec249a7354240cc851b921502ada33d1a/proof/a11y/17776/pr-17776-visual-proof.mp4
#17651 Enter on a row child control opens only that child action. Source PR #17789. Artifact folder: https://github.com/adamint/aspire/tree/a11y-artifacts-20260601042635/17651. Visual proof: https://raw.githubusercontent.com/adamint/aspire/cd33e79ec249a7354240cc851b921502ada33d1a/proof/a11y/17789/pr-17789-visual-proof.mp4
#17654 Resources tabs stay visible at 320px reflow. Source PR #17791. Artifact folder: https://github.com/adamint/aspire/tree/a11y-artifacts-20260601042635/17654. Visual proof: https://raw.githubusercontent.com/adamint/aspire/cd33e79ec249a7354240cc851b921502ada33d1a/proof/a11y/17791/pr-17791-visual-proof.mp4
#17469 Tabbing out of Aspire popups lands on the next logical control. Source PR #17793. Artifact folder: https://github.com/adamint/aspire/tree/a11y-artifacts-20260601042635/17469. Visual proof: https://raw.githubusercontent.com/adamint/aspire/cd33e79ec249a7354240cc851b921502ada33d1a/proof/a11y/17793/pr-17793-visual-proof.mp4

Validation

dotnet test --project tests/Aspire.Dashboard.Components.Tests/Aspire.Dashboard.Components.Tests.csproj --no-launch-profile -- --filter-class "*.AspireMenuButtonTests" --filter-class "*.AspireMenuTests" --filter-class "*.AspirePopupFocusNavigationTests" --filter-class "*.ResourcesTests" --filter-class "*.ResourceDetailsTests" --filter-class "*.ConsoleLogsTests" --filter-not-trait "quarantined=true" --filter-not-trait "outerloop=true"

Checklist

  • Is this feature complete?
    • Yes. Ready to ship.
    • No. Follow-up changes expected.
  • Are you including unit tests for the changes and scenario tests if relevant?
    • Yes
    • No
  • Did you add public API?
    • Yes
      • If yes, did you have an API Review for it?
        • Yes
        • No
      • Did you add <remarks /> and <code /> elements on your triple slash comments?
        • Yes
        • No
    • No
  • Does the change make any security assumptions or guarantees?
    • Yes
      • If yes, have you done a threat model and had a security review?
        • Yes
        • No
    • No

adamint and others added 14 commits June 4, 2026 17:55
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Stop Resources grid row activation from handling unmodified Enter events that originate on interactive controls. Add scoped JavaScript registration and tests for module initialization and key handling.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Stack the Resources view tabs at ultra-low width so the selected Graph tab remains visible under reflow. Add targeted component coverage for the responsive tab orientation.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add opt-in Aspire popup focus navigation for menus and filter/URL popovers so Tab and Shift+Tab close or move focus predictably instead of resetting to the first page control. Cover JS interop wiring and lifecycle behavior.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 4, 2026

🚀 Dogfood this PR with:

⚠️ WARNING: Do not do this without first carefully reviewing the code of this PR to satisfy yourself it is safe.

curl -fsSL https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- 17926

Or

  • Run remotely in PowerShell:
iex "& { $(irm https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.ps1) } 17926"

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR consolidates multiple Aspire Dashboard Resources page accessibility fixes, improving keyboard/screen reader behavior for menu expanded state, focus restoration, tab reflow at narrow widths, and predictable Tab/Escape navigation in popups/menus.

Changes:

  • Adds opt-in popup/menu keyboard focus navigation (Tab/Shift+Tab/Escape) via new JS handlers + a small Blazor wrapper component.
  • Fixes Resources page keyboard interaction issues (View options focus restoration, preventing nested row controls from also triggering row activation) and improves tab header reflow/visibility at narrow widths.
  • Expands automated coverage with new bUnit tests, a Node-based JS test for the Resources grid keyboard module, and a Playwright integration test for focus order.
Show a summary per file
File Description
tests/Aspire.Dashboard.Tests/Integration/Playwright/ResourcesTests.cs Adds a Playwright regression test validating Tab focus after closing the View options menu.
tests/Aspire.Dashboard.Tests/Integration/Playwright/Infrastructure/MockDashboardClient.cs Allows injecting a custom resources list for integration scenarios.
tests/Aspire.Dashboard.Tests/Integration/Playwright/Infrastructure/DashboardServerFixture.cs Adds fixture extensibility to provide custom resource data via the mock dashboard client.
tests/Aspire.Dashboard.Components.Tests/Shared/ResourceSetupHelpers.cs Stubs the new Resources page JS module initialization/disposal for component tests.
tests/Aspire.Dashboard.Components.Tests/Shared/FluentUISetupHelpers.cs Adds global JSInterop stubs for popup keyboard navigation used by new/updated components.
tests/Aspire.Dashboard.Components.Tests/Pages/ResourcesTests.cs Adds tests for ultra-low-width tab orientation, JS module behavior, and focus restoration wiring.
tests/Aspire.Dashboard.Components.Tests/Pages/ConsoleLogsTests.cs Updates menu-item activation tests to invoke menu-item models directly (async) rather than clicking DOM elements.
tests/Aspire.Dashboard.Components.Tests/Controls/ResourceDetailsTests.cs Updates masking toggle tests to invoke Aspire menu item models directly.
tests/Aspire.Dashboard.Components.Tests/Controls/AspirePopupFocusNavigationTests.cs Adds tests for initializing/closing popup keyboard navigation.
tests/Aspire.Dashboard.Components.Tests/Controls/AspireMenuTests.cs Adds tests covering menu keyboard navigation init/dispose and focus restoration behavior.
tests/Aspire.Dashboard.Components.Tests/Controls/AspireMenuButtonTests.cs Adds a regression test ensuring aria-expanded is reliably true/false.
src/Aspire.Dashboard/wwwroot/js/app.js Introduces initializeAspirePopupKeyboardNavigation / disposeAspirePopupKeyboardNavigation and focus traversal helpers.
src/Aspire.Dashboard/Components/ResourcesGridColumns/UrlsColumnDisplay.razor Wraps overflow URL popover content in popup focus navigation to fix Tab order.
src/Aspire.Dashboard/Components/Pages/Resources.razor.js Adds a Resources-scoped JS module to stop row activation when Enter originates from interactive descendants.
src/Aspire.Dashboard/Components/Pages/Resources.razor.css Improves tab header overflow behavior so focused/selected tabs remain reachable/visible at narrow widths.
src/Aspire.Dashboard/Components/Pages/Resources.razor.cs Imports/initializes/disposes the new Resources grid keyboard activation JS module.
src/Aspire.Dashboard/Components/Pages/Resources.razor Enables focus restoration on View options; adds popup focus navigation wrapper; makes tabs vertical at ultra-low width; captures grid container element reference.
src/Aspire.Dashboard/Components/Controls/Chart/ChartFilters.razor Wraps chart filter popover content in popup focus navigation for predictable Tab behavior.
src/Aspire.Dashboard/Components/Controls/AspirePopupFocusNavigation.razor.cs New wrapper component that wires popup open/close state to JS keyboard navigation logic.
src/Aspire.Dashboard/Components/Controls/AspirePopupFocusNavigation.razor New markup wrapper providing a stable popup root element id.
src/Aspire.Dashboard/Components/Controls/AspireMenuButton.razor.cs Adds RestoreFocusOnItemClick parameter (documented) to enable opt-in focus restoration.
src/Aspire.Dashboard/Components/Controls/AspireMenuButton.razor Ensures aria-expanded is always "true"/"false" and forwards focus-restore option to AspireMenu.
src/Aspire.Dashboard/Components/Controls/AspireMenu.razor.cs Adds JS-driven popup keyboard navigation and opt-in focus restoration after item click; manages disposal.
src/Aspire.Dashboard/Components/Controls/AspireMenu.razor Assigns an id to the underlying FluentMenu to support JS focus navigation targeting.

Copilot's findings

  • Files reviewed: 24/24 changed files
  • Comments generated: 4

Comment thread src/Aspire.Dashboard/Components/Pages/Resources.razor.js
Comment thread tests/Aspire.Dashboard.Components.Tests/Controls/AspireMenuTests.cs
Comment thread tests/Aspire.Dashboard.Components.Tests/Controls/AspireMenuTests.cs Outdated
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copy link
Copy Markdown
Member Author

@adamint adamint left a comment

Choose a reason for hiding this comment

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

Reviewed the Resources accessibility changes with multiple passes and ran the targeted dashboard component validation. I did not find any blocking issues.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment