Skip to content

Conversation

@TudorGR
Copy link

@TudorGR TudorGR commented Oct 23, 2025

Fixes #4904

This PR adds full keyboard navigation support to breadcrumb dropdown menus. Previously, while breadcrumb entries could be navigated using Tab, the dropdown lists themselves were not keyboard accessible once opened.

Implemented features:

  • Arrow keys (↑/↓) navigate through list items
  • Enter key opens the selected entity
  • Escape key closes the dropdown
  • Search input auto-focuses when dropdown opens
  • Typing alphanumeric keys or Backspace/Delete automatically focuses the search input
  • Tab key navigation handled via existing focusTrap action
  • Selected items are focused and smoothly scrolled into view

Technical details

  • Modified mathesar_ui/src/components/breadcrumb/BreadcrumbSelector.svelte
  • Added focusTrap action to dropdown content container as suggested in the issue
  • Implemented handleKeyDown() function to handle keyboard events (Escape, ArrowUp, ArrowDown, Enter, alphanumeric keys)
  • Added scrollToSelected() helper function to maintain visibility of selected items
  • Tracks filtered entries using allFilteredEntries computed value for accurate navigation
  • Maintains selectedIndex state for current selection
  • All existing functionality preserved and no breaking changes

Screenshots

Will be added after testing in live environment

Checklist

  • My pull request has a descriptive title (not a vague title like Update index.md).
  • My pull request targets the develop branch of the repository
  • My commit messages follow best practices.
  • My code follows the established code style of the repository.
  • I added tests for the changes I made (if applicable).
  • I added or updated documentation (if applicable).
  • I tried running the project locally and verified that there are no
    visible errors.

Developer Certificate of Origin

Developer Certificate of Origin
Developer Certificate of Origin
Version 1.1

Copyright (C) 2004, 2006 The Linux Foundation and its contributors.
1 Letterman Drive
Suite D4700
San Francisco, CA, 94129

Everyone is permitted to copy and distribute verbatim copies of this
license document, but changing it is not allowed.


Developer's Certificate of Origin 1.1

By making a contribution to this project, I certify that:

(a) The contribution was created in whole or in part by me and I
    have the right to submit it under the open source license
    indicated in the file; or

(b) The contribution is based upon previous work that, to the best
    of my knowledge, is covered under an appropriate open source
    license and I have the right under that license to submit that
    work with modifications, whether created in whole or in part
    by me, under the same open source license (unless I am
    permitted to submit under a different license), as indicated
    in the file; or

(c) The contribution was provided directly to me by some other
    person who certified (a), (b) or (c) and I have not modified
    it.

(d) I understand and agree that this project and the contribution
    are public and that a record of the contribution (including all
    personal information I submit with it, including my sign-off) is
    maintained indefinitely and may be redistributed consistent with
    this project or the open source license(s) involved.

@pavish pavish added the pr-status: review A PR awaiting review label Oct 24, 2025
@pavish pavish self-assigned this Oct 24, 2025
Copy link
Member

@pavish pavish left a comment

Choose a reason for hiding this comment

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

@TudorGR Thanks for the PR!

This is a good start, I've raised a few comments that need to be resolved in order to get the PR merged.

Comment on lines 109 to 119
// For alphanumeric keys and editing keys, focus the search input
if (
event.key.length === 1 ||
event.key === 'Backspace' ||
event.key === 'Delete'
) {
// If the search input isn't already focused, focus it
if (document.activeElement !== textInputEl) {
textInputEl?.focus();
}
}
Copy link
Member

Choose a reason for hiding this comment

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

This logic is not triggered since this keydown event handler is only placed on the top level dom element (.entity-switcher-content). When an item is focused (in this case, .breadcrumb-selector-row a), the keydown event is dispatched from that element.

Comment on lines 101 to 106
event.preventDefault();
const selectedEntry = allFilteredEntries[selectedIndex];
if (selectedEntry) {
window.location.href = selectedEntry.href;
}
return;
Copy link
Member

Choose a reason for hiding this comment

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

When an anchor item (or any focusable item) is focused, pressing the enter key should perform its default action.

event.preventDefault() should not be used in this case. Setting window.location.href reloads the entire page without allowing the frontend router to take over the navigation.

Comment on lines 77 to 85
if (event.key === 'ArrowDown') {
event.preventDefault();
selectedIndex = Math.min(
selectedIndex + 1,
allFilteredEntries.length - 1,
);
scrollToSelected();
return;
}
Copy link
Member

Choose a reason for hiding this comment

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

When the user reaches the final item on the list, and ArrowDown is triggered, the selection should loop back to the search box, and then the first item.

Comment on lines 87 to 98
if (event.key === 'ArrowUp') {
event.preventDefault();
if (selectedIndex <= 0) {
// Focus search input when at the top
selectedIndex = -1;
textInputEl?.focus();
} else {
selectedIndex = Math.max(selectedIndex - 1, 0);
scrollToSelected();
}
return;
}
Copy link
Member

Choose a reason for hiding this comment

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

Similar to the previous comment, when ArrowUp is triggered when the user is at the first item in the list, the search box should be focused. ArrowUp on the search box should focus the last item on the list.

);
const selectedLink = links[selectedIndex] as HTMLElement;
if (selectedLink) {
selectedLink.focus();
Copy link
Member

Choose a reason for hiding this comment

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

The anchor elements are focused as expected, however, its not visible to the user. The parent list (li) element should have a css style when the anchor it contains gets focused. This style should be similar to the hover style it currently has. The :has css selector can be used to handle this.

@pavish pavish assigned TudorGR and unassigned pavish Oct 27, 2025
@pavish pavish added pr-status: revision A PR awaiting follow-up work from its author after review and removed pr-status: review A PR awaiting review labels Oct 27, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr-status: revision A PR awaiting follow-up work from its author after review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Make breadcrumb list keyboard navigable

2 participants