Skip to content

feat(select): improve keyboard navigation in single select#1724

Merged
kabaros merged 5 commits intodhis2:alphafrom
EdsonNhancale:LIBS-812/keyboard-accessible
Feb 17, 2026
Merged

feat(select): improve keyboard navigation in single select#1724
kabaros merged 5 commits intodhis2:alphafrom
EdsonNhancale:LIBS-812/keyboard-accessible

Conversation

@EdsonNhancale
Copy link
Copy Markdown

@EdsonNhancale EdsonNhancale commented Jan 31, 2026

fixes https://dhis2.atlassian.net/browse/LIBS-812

  • Add focus method to Input component for programmatic focus control
  • Add tabIndex and onKeyDown to OptionsList to enable keyboard navigation on the listbox
  • Forward ref to Filter component to allow focusing the filter input
  • When ArrowUp is pressed on the first option, focus moves to the filter input
  • When ArrowDown is pressed in filter input, focus moves to the listbox
  • This improves accessibility and user experience for keyboard-only users

Implements LIBS-812


Description

Enhanced keyboard accessibility for the single select component. Added focus control to the Input, forwarded ref to Filter, and enabled keyboard navigation in OptionsList. Pressing ArrowUp from the first option moves focus to the filter, and ArrowDown from the filter moves focus to the list, improving usability for keyboard-only users.


Known issues

  • issue

Checklist

  • API docs are generated
  • Tests were added
  • Storybook demos were added

All points above should be relevant for feature PRs. For bugfixes, some points might not be relevant. In that case, just check them anyway to signal the work is done.


Screenshots

Simple single select - Made with Clipchamp (1)

- Add focus method to Input component for programmatic focus control
- Add tabIndex and onKeyDown to OptionsList to enable keyboard navigation on the listbox
- Forward ref to Filter component to allow focusing the filter input
- When ArrowUp is pressed on the first option, focus moves to the filter input
- When ArrowDown is pressed in filter input, focus moves to the listbox
- This improves accessibility and user experience for keyboard-only users
@EdsonNhancale EdsonNhancale requested a review from a team as a code owner January 31, 2026 15:50
Copy link
Copy Markdown
Collaborator

@kabaros kabaros left a comment

Choose a reason for hiding this comment

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

thanks for this @EdsonNhancale - it's much more complicated than I anticipated. Some comments here .. let me know if anything doesn't make sense.

onFilterChange,
onFilterInputKeyDown,
filterRef,
onOptionsKeyDown,
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

is this onOptionsKeyDown used at all - I removed it all the way down, and everything seems to work as it is (since the hook has the reference to filter and controls focus)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Hello, @kabaros , that listBoxRef.current?.focus() is what makes onOptionsKeyDown relevant.
If we remove it, it won't work very well.

Comment thread components/input/src/input/input.js Outdated
}

focus() {
this.inputRef.current.focus()
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

just in case, make this a bit more defensive this.inputRef.current?.focus?.()

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

done

<div
ref={ref}
role="listbox"
tabIndex="-1"
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I don't think this is necessary? actually when we don't add it, we get the nice effect that we can continue typing while going up and down the list

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

I use tabIndex="-1" to move the focus to the component. I think that if we remove it, it won't work properly.

Ensure the focus method does not throw when inputRef.current is null or undefined, which can occur in certain lifecycle states.
@kabaros kabaros changed the base branch from master to alpha February 16, 2026 15:10
Reorder PropTypes in simple-single-select menu components to maintain a consistent and logical grouping. This improves code readability and maintainability.
@sonarqubecloud
Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
2 New issues
2 New Code Smells (required ≤ 0)

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE

@kabaros kabaros merged commit 88dc95d into dhis2:alpha Feb 17, 2026
3 of 5 checks passed
dhis2-bot added a commit that referenced this pull request Feb 17, 2026
# [10.13.0-alpha.1](v10.12.8...v10.13.0-alpha.1) (2026-02-17)

### Features

* **select:** improve keyboard navigation in single select ([#1724](#1724)) ([88dc95d](88dc95d))
@dhis2-bot
Copy link
Copy Markdown
Contributor

🎉 This PR is included in version 10.13.0-alpha.1 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants