fix(Menu): allow Tab to move focus out of non-modal DropdownMenu#2747
Conversation
The Tab key was unconditionally prevented in MenuContentImpl, blocking focus from leaving even non-modal menus. Tab should still be prevented for modal menus (trapFocus=true, handled by FocusScope). Now Tab key default prevention is gated on trapFocus.value, so non-modal menus allow Tab to naturally move focus to the next focusable element on the page. Closes unovue#2296
📝 WalkthroughWalkthrough
ChangesDropdownMenu Tab behavior
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
commit: |
|
Thanks for the fix — the gating on Could you add a regression test before we merge? There's currently no Tab-keydown coverage in the Menu/DropdownMenu suites, so "all tests pass" doesn't actually exercise this behavior. Ideally:
One more thing to confirm: submenus omit |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
packages/core/src/DropdownMenu/DropdownMenu.test.ts (1)
117-170: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winUse the repository’s test stack conventions for this suite.
These new interaction tests are written with
mount; guidelines forpackages/core/src/**/*.test.tsrequire@testing-library/vue(andvitest-axewhere applicable). Please align this block to that stack for consistency.As per coding guidelines, "
packages/core/src/**/*.test.ts: Write tests using vitest, jsdom,@testing-library/vue, and vitest-axe; include axe accessibility checks for new components".🤖 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 `@packages/core/src/DropdownMenu/DropdownMenu.test.ts` around lines 117 - 170, The new DropdownMenu interaction tests are using mount instead of the repository’s required testing stack. Update the DropdownMenuTabTest coverage to use vitest with jsdom and `@testing-library/vue` queries/events, matching the conventions used in packages/core/src/**/*.test.ts, and add vitest-axe accessibility coverage where appropriate. Keep the same Tab prevention assertions by locating the menu/submenu through user-facing queries rather than wrapper.findAll/mount-specific APIs.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 `@packages/core/src/DropdownMenu/DropdownMenu.test.ts`:
- Around line 116-134: The Tab focus test in DropdownMenuTabTest is
self-fulfilling because it manually focuses the “After” button before asserting
activeElement. Update the test so it verifies actual Tab behavior in
DropdownMenu.test by either removing the activeElement assertion and only
checking that the keydown event is not prevented, or by using a real
tab-navigation helper to move focus out of the non-modal menu before asserting
the focused button.
---
Nitpick comments:
In `@packages/core/src/DropdownMenu/DropdownMenu.test.ts`:
- Around line 117-170: The new DropdownMenu interaction tests are using mount
instead of the repository’s required testing stack. Update the
DropdownMenuTabTest coverage to use vitest with jsdom and `@testing-library/vue`
queries/events, matching the conventions used in packages/core/src/**/*.test.ts,
and add vitest-axe accessibility coverage where appropriate. Keep the same Tab
prevention assertions by locating the menu/submenu through user-facing queries
rather than wrapper.findAll/mount-specific APIs.
🪄 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: defaults
Review profile: CHILL
Plan: Pro
Run ID: 1e0f432e-8651-42f5-8d2c-bb4ccf70c28b
📒 Files selected for processing (2)
packages/core/src/DropdownMenu/DropdownMenu.test.tspackages/core/src/Menu/MenuContentImpl.vue
cc63268 to
e64e914
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 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 `@packages/core/src/DropdownMenu/DropdownMenu.test.ts`:
- Line 2: The named import order in DropdownMenu.test.ts violates
perfectionist/sort-named-imports. Reorder the imported testing-library symbols
in the existing import statement so the named imports are sorted consistently,
keeping the change limited to the import line in DropdownMenu.test.
🪄 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: defaults
Review profile: CHILL
Plan: Pro
Run ID: 37b2b2f1-89e7-4a84-8dfe-8ab27ca8121b
📒 Files selected for processing (2)
packages/core/src/DropdownMenu/DropdownMenu.test.tspackages/core/src/Menu/MenuContentImpl.vue
🚧 Files skipped from review as they are similar to previous changes (1)
- packages/core/src/Menu/MenuContentImpl.vue
Description
Fixes #2296 — Unable to use Tab to move focus outside of open, non-modal DropdownMenu.
Root Cause
MenuContentImpl.vueunconditionally calledevent.preventDefault()on Tab keydown when inside the menu. This was intended to prevent Tab from navigating between menu items (menus use arrow keys), but it had the side effect of completely disabling Tab — focus could never leave the menu.Fix
Gate the Tab
preventDefaultontrapFocus.value. When the menu is modal (trapFocus=true), Tab is still prevented (FocusScope handles focus trapping). When non-modal (trapFocus=false, which is the default for DropdownMenu), Tab is allowed to naturally move focus to the next focusable element on the page, per the WAI-ARIA menubar keyboard interaction pattern.Testing
All 21 tests pass: Menu (6), DropdownMenu (6), ContextMenu (3), Menubar (6)
Summary by CodeRabbit
Tabbehavior in non-modal menus so users can move focus forward instead of being trapped.Tabfocus handling for modal menus, including nested submenus, preventing unintended focus changes.Tabbehavior for modal vs non-modal menus and nested submenu keydown prevention.