[EuiSelectable][EuiComboBox] Fix duplicated screen reader announcements of option name and checked state - #9850
Conversation
…uncement The checked state of a selectable list item is already conveyed natively via aria-checked/aria-selected, so the additional visually-hidden "Checked option." text caused screen readers (e.g. NVDA) to announce the state twice. Fixes elastic/kibana#216048 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…element A title attribute on the option <li> maps to the option's accessible description (HTML-AAM), which screen readers announce in addition to the accessible name - so the option name was read twice. Moving the title to the inner text element keeps the hover tooltip for truncated text without affecting the option's name/description computation. Part of elastic/kibana#216157 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR improves accessibility for option rows in EuiSelectable and EuiComboBox by eliminating duplicate screen reader announcements caused by redundant visually-hidden “checked” text and by title attributes being applied to the option container element.
Changes:
- Removed the screen-reader-only “Checked option.” text for checked selectable options (relies on native
aria-checked/aria-selectedinstead). - Moved truncation
titleattributes from the option element to the inner text element for both selectable and combo box options. - Widened
EuiListItemLayout’stextPropstyping to allow passing standard HTML attributes (e.g.title), and updated tests/snapshots/a11y assertions plus a changelog entry.
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| packages/eui/src/components/selectable/selectable_list/selectable_list_item.tsx | Removes redundant checked SR text; moves title to the inner text span via textProps. |
| packages/eui/src/components/selectable/selectable_list/selectable_list_item.test.tsx | Adds a regression test asserting title is not on the option element but on the text element. |
| packages/eui/src/components/selectable/selectable_list/snapshots/selectable_list.test.tsx.snap | Updates snapshots for title placement changes. |
| packages/eui/src/components/selectable/selectable_list/snapshots/selectable_list_item.test.tsx.snap | Updates snapshots to reflect removal of “Checked option.” SR-only text. |
| packages/eui/src/components/selectable/snapshots/selectable.test.tsx.snap | Updates snapshots for title placement changes in selectable render output. |
| packages/eui/src/components/list_item_layout/_list_item_layout.tsx | Widens textProps type to accept HTML attributes (enables title on text span). |
| packages/eui/src/components/filter_group/filter_group.a11y.tsx | Updates Cypress a11y assertion to reflect removal of “Checked option.” text. |
| packages/eui/src/components/combo_box/combo_box_options_list/combo_box_options_list.tsx | Moves truncation title off the option element and onto the inner text element. |
| packages/eui/src/components/combo_box/snapshots/combo_box.test.tsx.snap | Updates snapshots for combo box option title placement changes. |
| packages/eui/changelogs/upcoming/9850.md | Adds changelog entry documenting the accessibility improvements. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
…the option element Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
acstll
left a comment
There was a problem hiding this comment.
Thanks you @alexwizp, code changes look good. I tested with Chrome/NVDA and it works as expected.
(I found sometimes there's a space with a dot after the option name e.g. Rhea . Checked foo bar that gets literally announced as "dot", but that's out of the scope of this PR)
Not approving yet because it's likely that the title change might cause a couple of tests in Kibana to break. Tests using selectors such as .euiSelectableListItem[title="${intervalTitle}"]. Ideally we deal with those before/during merging so upgrading after releasing is easier…
Kibana Regression Integration TestStatus: 💔 Kibana CI failed Please check Kibana CI logs for details. |
Co-authored-by: Arturo Castillo Delgado <arturo@arturu.com>
acstll
left a comment
There was a problem hiding this comment.
🟢 Thanks for the fix and addressing the feedback (prep commits)!
💚 Build Succeeded
History
|
💚 Build Succeeded
History
|
## Dependency updates `@elastic/eui` - v121.0.0 ⏩ v122.0.0 `@elastic/eui-illustrations` - v1.0.2 ⏩ v1.1.0 `@elastic/eui-test-helpers` - v1.6.0 ⏩ v1.7.0 ## Changes - Cherry-picked staged Kibana prep commits from `kibana-prep-commits`: - #288940 (`1fdf41c`) — type `EuiSuperSelect` refs as `EuiSuperSelectRef` following the breaking `ref` change in elastic/eui#9972 - #290240 (`54cae3c`) — update tests, page objects, the EUI i18n mapping, and translation files for the removed `euiSelectableListItem.checkedOption` screen-reader text (elastic/eui#9850) - Synced EUI i18n tokens: added `euiKeyboardShortcuts.cmd`, `euiKeyboardShortcuts.copyTitle`, and `euiKeyboardShortcuts.copyDescription` to `i18n_eui_mapping.tsx` and updated the `i18n_service` snapshot ## Package updates ### `@elastic/eui` [v122.0.0](https://github.com/elastic/eui/blob/main/packages/eui/changelogs/CHANGELOG_2026.md) - Added Ctrl/Cmd+C support on `EuiDataGrid` to copy the focused cell value when no text is selected ([#9995](elastic/eui#9995)) **Bug fixes** - Fixed `EuiDataGrid` copy/paste shifting body rows one column right of the headers when control columns were present ([#9954](elastic/eui#9954)) **Breaking changes** - Changed the `ref` of `EuiSuperSelect` from the class instance to an `EuiSuperSelectRef` object, which exposes `openPopover()` and `closePopover()` ([#9972](elastic/eui#9972)) **Accessibility** - Improved the accessibility of `EuiSelectable` by removing redundant "Checked option." screen-reader text (checked state is already conveyed via `aria-checked`/`aria-selected`) ([#9850](elastic/eui#9850)) - Improved the accessibility of `EuiSelectable` and `EuiComboBox` by moving the `title` attribute to the inner text element, preventing duplicate screen-reader announcements of option names ([#9850](elastic/eui#9850)) ### `@elastic/eui-illustrations` [v1.1.0](https://github.com/elastic/eui/blob/main/packages/illustrations/changelogs/CHANGELOG_2026.md) - Added `attachments`, `detection`, `discovery`, `fieldExtraction`, `generatePreview`, `knowledgeIndicator`, `noData`, `processorsError`, `processorsLoading`, and `processorsPreview` illustrations ([#10001](elastic/eui#10001)) ### `@elastic/eui-test-helpers` [v1.7.0](https://github.com/elastic/eui/blob/main/packages/test-helpers/changelogs/CHANGELOG_2026.md) - Added `EuiTreeViewObject`, a Playwright Component Object for `EuiTreeView` ([#10025](elastic/eui#10025)) - Added `EuiToolTipObject`, a Playwright Component Object for `EuiToolTip` ([#10026](elastic/eui#10026)) - Added `EuiContextMenuObject`, a Playwright Component Object for `EuiContextMenu` ([#10013](elastic/eui#10013)) - Added `EuiColorPickerObject`, a Playwright Component Object for `EuiColorPicker` ([#10020](elastic/eui#10020)) **Bug fixes** - Fixed Component Objects not finding components whose `data-test-subj` holds several space-separated tokens, such as `EuiColorPicker`. The root now matches one token, following Kibana's `data-test-subj` convention ([#10015](elastic/eui#10015)) --------- Co-authored-by: Weronika Olejniczak <weronika.olejniczak@elastic.co> Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: Alexey Antonov <alexwizp@gmail.com> Co-authored-by: Lene Gadewoll <lene.gadewoll@elastic.co> Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
## Dependency updates `@elastic/eui` - v121.0.0 ⏩ v122.0.0 `@elastic/eui-illustrations` - v1.0.2 ⏩ v1.1.0 `@elastic/eui-test-helpers` - v1.6.0 ⏩ v1.7.0 ## Changes - Cherry-picked staged Kibana prep commits from `kibana-prep-commits`: - elastic#288940 (`1fdf41c`) — type `EuiSuperSelect` refs as `EuiSuperSelectRef` following the breaking `ref` change in elastic/eui#9972 - elastic#290240 (`54cae3c`) — update tests, page objects, the EUI i18n mapping, and translation files for the removed `euiSelectableListItem.checkedOption` screen-reader text (elastic/eui#9850) - Synced EUI i18n tokens: added `euiKeyboardShortcuts.cmd`, `euiKeyboardShortcuts.copyTitle`, and `euiKeyboardShortcuts.copyDescription` to `i18n_eui_mapping.tsx` and updated the `i18n_service` snapshot ## Package updates ### `@elastic/eui` [v122.0.0](https://github.com/elastic/eui/blob/main/packages/eui/changelogs/CHANGELOG_2026.md) - Added Ctrl/Cmd+C support on `EuiDataGrid` to copy the focused cell value when no text is selected ([elastic#9995](elastic/eui#9995)) **Bug fixes** - Fixed `EuiDataGrid` copy/paste shifting body rows one column right of the headers when control columns were present ([elastic#9954](elastic/eui#9954)) **Breaking changes** - Changed the `ref` of `EuiSuperSelect` from the class instance to an `EuiSuperSelectRef` object, which exposes `openPopover()` and `closePopover()` ([elastic#9972](elastic/eui#9972)) **Accessibility** - Improved the accessibility of `EuiSelectable` by removing redundant "Checked option." screen-reader text (checked state is already conveyed via `aria-checked`/`aria-selected`) ([elastic#9850](elastic/eui#9850)) - Improved the accessibility of `EuiSelectable` and `EuiComboBox` by moving the `title` attribute to the inner text element, preventing duplicate screen-reader announcements of option names ([elastic#9850](elastic/eui#9850)) ### `@elastic/eui-illustrations` [v1.1.0](https://github.com/elastic/eui/blob/main/packages/illustrations/changelogs/CHANGELOG_2026.md) - Added `attachments`, `detection`, `discovery`, `fieldExtraction`, `generatePreview`, `knowledgeIndicator`, `noData`, `processorsError`, `processorsLoading`, and `processorsPreview` illustrations ([elastic#10001](elastic/eui#10001)) ### `@elastic/eui-test-helpers` [v1.7.0](https://github.com/elastic/eui/blob/main/packages/test-helpers/changelogs/CHANGELOG_2026.md) - Added `EuiTreeViewObject`, a Playwright Component Object for `EuiTreeView` ([elastic#10025](elastic/eui#10025)) - Added `EuiToolTipObject`, a Playwright Component Object for `EuiToolTip` ([elastic#10026](elastic/eui#10026)) - Added `EuiContextMenuObject`, a Playwright Component Object for `EuiContextMenu` ([elastic#10013](elastic/eui#10013)) - Added `EuiColorPickerObject`, a Playwright Component Object for `EuiColorPicker` ([elastic#10020](elastic/eui#10020)) **Bug fixes** - Fixed Component Objects not finding components whose `data-test-subj` holds several space-separated tokens, such as `EuiColorPicker`. The root now matches one token, following Kibana's `data-test-subj` convention ([elastic#10015](elastic/eui#10015)) --------- Co-authored-by: Weronika Olejniczak <weronika.olejniczak@elastic.co> Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: Alexey Antonov <alexwizp@gmail.com> Co-authored-by: Lene Gadewoll <lene.gadewoll@elastic.co> Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
Summary
EuiSelectable/EuiComboBoxoptions. Two changes:EuiSelectableListItem.titleattribute from the option<li>element to its inner text element (EuiSelectableandEuiComboBox).aria-checked/aria-selectedon the option<li>, so screen readers (e.g. NVDA) announced the checked state twice — once from the ARIA attribute ("checked 1 of 4") and once from the extra hidden text ("Checked option.").titleattribute on the option<li>maps to the option's accessible description (per HTML-AAM), which screen readers announce in addition to the accessible name — so the option name was read twice.euiSelectableListItem.checkedOptionstate string forchecked="on"inselectable_list_item.tsx. The "Excluded option." (checked="off") and "Mixed (indeterminate) option." (checked="mixed") state texts are kept, as those states are not (or not reliably) distinguishable from the ARIA attributes alone. Keyboard instructions ("To uncheck/exclude this option, press Enter.") are unchanged.EuiSelectableListItemnow interceptstitleand renders it on the.euiSelectableListItem__textspan viatextProps;EuiComboBoxOptionsListdoes the same foreuiComboBoxOptionitems. The native hover tooltip for CSS-truncated text is preserved (it now triggers over the text rather than the whole row), but thetitleno longer participates in the option's accessible name/description computation. Follows up on [EuiToolTip] Replace all title attributes with EuiToolTip #9643, which narrowed when thetitleis set.Screen reader output for a checked option "System", before → after:
API Changes
euiSelectableListItem.checkedOptioni18n tokenaria-checked/aria-selectedtitleattribute<li>, so it no longer becomes the option's accessible descriptiontextPropsCommonProps & HTMLAttributes<HTMLElement>) in addition toCommonPropsScreenshots
N/A — no visual changes; only visually-hidden screen reader text and attribute placement are affected (see before/after announcement text above).
Impact Assessment
Note: Most PRs should be tested in Kibana to help gauge their Impact before merging.
[title=...]on the<li>will need to target the inner text element instead — e.g. snapshot tests ofEuiSelectable/EuiComboBox/filter popover options.Impact level: 🟢 Low
Release Readiness
Documentation:N/A — no API or docs changesFigma:N/AMigration guide:N/AAdoption plan (new features):N/A — bug fixQA instructions for reviewer
EuiSelectabledemo with checked options (e.g. the Selectable docs or anEuiSearchBarfield_value_selectionfilter popover).titleattribute).EuiComboBoxoptions — the option name is announced only once.allowExclusions, navigate to an excluded option — "Excluded option." is still announced.EuiSelectable/EuiComboBox— the native browser tooltip with the full text still appears.Checklist before marking Ready for Review
QA: Tested docs changesN/Atitleplacement, and updated Cypress a11y assertionsBreaking changes: AddedN/Abreaking changelabelReviewer checklist