Skip to content

[EuiSelectable][EuiComboBox] Fix duplicated screen reader announcements of option name and checked state - #9850

Merged
alexwizp merged 10 commits into
elastic:mainfrom
alexwizp:216048-fix-duplicated-checked-announcement
Sep 10, 2026
Merged

alexwizp merged 10 commits into
elastic:mainfrom
alexwizp:216048-fix-duplicated-checked-announcement

Conversation

@alexwizp

@alexwizp alexwizp commented Jul 28, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • What: Fixed duplicate screen reader announcements for EuiSelectable / EuiComboBox options. Two changes:
    1. Removed the visually-hidden "Checked option." screen reader state text from EuiSelectableListItem.
    2. Moved the option title attribute from the option <li> element to its inner text element (EuiSelectable and EuiComboBox).
  • Why: Fixes [Analytics:MachineLearning:Notifications page]Duplicated announcement for checked options kibana#216048, and the EUI-side part of [Analytics:MachineLearning:AnomalyDetection:Jobs page]Duplicated announcement for checked options kibana#216157.
    • When an option is checked, its state is already conveyed natively via aria-checked/aria-selected on 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.").
    • A title attribute 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.
  • How:
    • Removed the euiSelectableListItem.checkedOption state string for checked="on" in selectable_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.
    • EuiSelectableListItem now intercepts title and renders it on the .euiSelectableListItem__text span via textProps; EuiComboBoxOptionsList does the same for euiComboBoxOption items. The native hover tooltip for CSS-truncated text is preserved (it now triggers over the text rather than the whole row), but the title no longer participates in the option's accessible name/description computation. Follows up on [EuiToolTip] Replace all title attributes with EuiToolTip #9643, which narrowed when the title is set.

Screen reader output for a checked option "System", before → after:

System System checked option to uncheck this option, press Enter. checked 1 of 4
(name from title-as-description and checked state each announced twice)

System checked 1 of 4 to uncheck this option, press Enter.

API Changes

component / parent prop / child change description
EuiSelectableListItem euiSelectableListItem.checkedOption i18n token Removed The "Checked option." screen-reader-only state text is no longer rendered; the checked state is announced natively via aria-checked/aria-selected
EuiSelectableListItem / EuiComboBox options title attribute Moved Rendered on the inner text element instead of the option <li>, so it no longer becomes the option's accessible description
EuiListItemLayout (internal) textProps Type widened Now accepts HTML attributes (CommonProps & HTMLAttributes<HTMLElement>) in addition to CommonProps

Screenshots

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.

  • 🔴 Breaking changes — None.
  • 💅 Visual changes — None.
  • 🧪 Test impact — Tests asserting the full text content of selectable options will no longer see "Checked option.", and tests selecting options by [title=...] on the <li> will need to target the inner text element instead — e.g. snapshot tests of EuiSelectable/EuiComboBox/filter popover options.
  • 🔧 Hard to integrate — No.

Impact level: 🟢 Low

Release Readiness

  • Documentation: N/A — no API or docs changes
  • Figma: N/A
  • Migration guide: N/A
  • Adoption plan (new features): N/A — bug fix

QA instructions for reviewer

  • Open any EuiSelectable demo with checked options (e.g. the Selectable docs or an EuiSearchBar field_value_selection filter popover).
  • With a screen reader running (NVDA/VoiceOver):
    • Navigate to a checked option — the option name and its checked state are each announced only once (no extra "Checked option." announcement, no repeated name from the title attribute).
    • Repeat for EuiComboBox options — the option name is announced only once.
    • With allowExclusions, navigate to an excluded option — "Excluded option." is still announced.
    • Navigate to a mixed option — "Mixed (indeterminate) option." is still announced.
    • Keyboard instructions ("To uncheck/exclude this option, press Enter.") are still announced where applicable.
  • Without a screen reader:
    • Hover a long, truncated option label in EuiSelectable/EuiComboBox — the native browser tooltip with the full text still appears.

Checklist before marking Ready for Review

  • Filled out all sections above
  • QA: Tested light/dark modes, high contrast, mobile, Chrome/Safari/Edge/Firefox, keyboard-only, screen reader
  • QA: Tested in CodeSandbox and Kibana
  • QA: Tested docs changes N/A
  • Tests: Updated Jest snapshots, added a regression test for the title placement, and updated Cypress a11y assertions
  • Changelog: Added changelog entry
  • Breaking changes: Added breaking change label N/A

Reviewer checklist

  • Approved Impact Assessment — Acceptable to merge given the consumer impact.
  • Approved Release Readiness — Docs, Figma, and migration info are sufficient to ship.

alexwizp and others added 3 commits July 28, 2026 13:40
…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>
@alexwizp alexwizp changed the title [EuiSelectable] Remove redundant "Checked option." screen reader announcement [EuiSelectable][EuiComboBox] Fix duplicated screen reader announcements of option name and checked state Jul 28, 2026
@alexwizp
alexwizp marked this pull request as ready for review August 10, 2026 12:36
@alexwizp
alexwizp requested a review from a team as a code owner August 10, 2026 12:36
Copilot AI lite review requested due to automatic review settings August 10, 2026 12:36

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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-selected instead).
  • Moved truncation title attributes from the option element to the inner text element for both selectable and combo box options.
  • Widened EuiListItemLayout’s textProps typing 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>
@weronikaolejniczak
weronikaolejniczak requested review from weronikaolejniczak and removed request for weronikaolejniczak August 12, 2026 15:09
@acstll
acstll self-requested a review September 4, 2026 08:42

@acstll acstll left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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…

Comment thread packages/eui/changelogs/upcoming/9850.md Outdated
@github-actions

github-actions Bot commented Sep 7, 2026 •

Copy link
Copy Markdown

Kibana Regression Integration Test

Status: 💔 Kibana CI failed
Branch: update-dependencies/1788775237
Kibana PR: elastic/kibana#289556

Please check Kibana CI logs for details.

@acstll acstll removed the ci:regression-integration-test-kibana Run a Regression Integration Test in Kibana against this PR label Sep 10, 2026

@acstll acstll left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟢 Thanks for the fix and addressing the feedback (prep commits)!

@infra-vault-gh-plugin-prod

Copy link
Copy Markdown

💚 Build Succeeded

History

@infra-vault-gh-plugin-prod

Copy link
Copy Markdown

💚 Build Succeeded

History

@alexwizp
alexwizp merged commit 7e7cb0b into elastic:main Sep 10, 2026
8 checks passed
eokoneyo added a commit to elastic/kibana that referenced this pull request Sep 17, 2026
## 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>
ppisljar pushed a commit to ppisljar/kibana that referenced this pull request Sep 21, 2026
## 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>
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.

[Analytics:MachineLearning:Notifications page]Duplicated announcement for checked options

3 participants