Skip to content

Conversation

@maximo-macchi-cb
Copy link
Contributor

What changed? Why?

This PR addressees two accessibility related bugs:

  1. Tab key should close listbox menu, select the focused item, and shift focus back to the UI
  2. Aria-labels not announcing selected value for <Select> / <Combobox>

Root cause (required for bugfixes)

Bug 1
In <DefaultSelectOption>, there was no key handler when the Tab key is pressed. Therefore, it followed the normal focus order logic and shifted focus to the next menu item.

This was addressed by calling event.preventDefault() on the keypress event and using custom logic. In <FocusTrap> an event.defaultPrevented check is added to allow customers to override the <FocusTrap> keyboard behavior without needing to adjust the disableFocusTrap prop.

Bug 2
Select / Combobox and their corresponding default control components were only passing the accessibilityLabel prop value to aria-label.

This has been updated so aria-label receives both the accessibilityLabel and the selected value or placeholder as one concatenated string.

UI changes

iOS Old iOS New
old screenshot new screenshot
Android Old Android New
old screenshot new screenshot
Web Old Web New
old screenshot new screenshot

Testing

How has it been tested?

  • Unit tests
  • Interaction tests
  • Pseudo State tests
  • Manual - Web
  • Manual - Android (Emulator / Device)
  • Manual - iOS (Emulator / Device)

Testing instructions

Illustrations/Icons Checklist

Required if this PR changes files under packages/illustrations/** or packages/icons/**

  • verified visreg changes with Terran (include link to visreg run/approval)
  • all illustration/icons names have been reviewed by Dom and/or Terran

Change management

type=routine
risk=low
impact=sev5

automerge=false

@maximo-macchi-cb maximo-macchi-cb self-assigned this Dec 15, 2025
@cb-heimdall
Copy link
Collaborator

cb-heimdall commented Dec 15, 2025

🟡 Heimdall Review Status

Requirement Status More Info
Reviews 🟡 0/1
Denominator calculation
Show calculation
1 if user is bot 0
1 if user is external 0
2 if repo is sensitive 0
From .codeflow.yml 1
Additional review requirements
Show calculation
Max 0
0
From CODEOWNERS 1
Global minimum 0
Max 1
1
1 if commit is unverified 0
Sum 1
CODEOWNERS 🟡 See below

🟡 CODEOWNERS

Code Owner Status Calculation
ui-systems-eng-team 🟡 0/1
Denominator calculation
Additional CODEOWNERS Requirement
Show calculation
Sum 0
0
From CODEOWNERS 1
Sum 1

() => (
<Pressable disabled={disabled} onPress={() => setOpen((s) => !s)}>
<Pressable
accessible={customEndNode ? true : false}
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: hmm what if the end node is something that needs focus?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That's the purpose of this conditional value for the accessible prop! If a custom end node is passed in, we assume it may need to receive focus so accessible is set to true. The default end node is the <AnimatedCaret> which doesn't need to receive focus so it's false.

The green highlight is the accessible element in the mobile <DefaultSelectControl>. The end piece not highlighted is the default end node but pressing on it still opens the menu.

Screenshot 2025-12-15 at 12 04 32 PM

cb-ekuersch
cb-ekuersch previously approved these changes Dec 15, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Development

Successfully merging this pull request may close these issues.

3 participants