Skip to content

[EuiSelectableList] scrollable-region-focusable axe violation in non-virtualized mode #9517

@justinkambic

Description

@justinkambic

Reported by

@elastic/obs-exploration-team

Describe the bug

EuiSelectableList triggers an axe scrollable-region-focusable violation in non-virtualized mode. The .euiSelectableList__list wrapper <div> has overflow-y: auto applied via the euiYScrollWithShadows() mixin, but is given tabindex="-1" programmatically (via removeScrollableTabStop) and carries no accessible name or role. This makes the scrollable region unreachable by keyboard, violating the axe rule.

The virtualized path already handles this correctly — data-skip-axe="scrollable-region-focusable" is set on the FixedSizeList outer container. The non-virtualized path has no equivalent.

Impact and severity

  • Axe severity: Serious
  • End-user impact: Keyboard-only users cannot scroll the selectable list container in non-virtualized mode, potentially missing options that are off-screen.
  • Workaround: Callers can exclude .euiSelectableList__list from their axe scans, but this papers over the issue rather than fixing it.

Environment and versions

  • EUI version: 113
  • React version: 18
  • Kibana version (if applicable): 9.4.0
  • Browser: Chromium (via Playwright)
  • Operating System: macOS

Minimum reproducible sandbox

Render an EuiSelectable with fewer items than the virtualization threshold (default: 100) and run axe against it. The EuiSelectable examples on eui.elastic.co should reproduce this directly — open any example with a short list and run axe.run() in the browser console.

To Reproduce

  1. Render an EuiSelectable with a small list (fewer than 100 items, so virtualization is not used)
  2. Open the breakdown selector dropdown so the selectable list is visible
  3. Run axe against the rendered component (e.g. via axe.run() in the console, or via Playwright + @axe-core/playwright)
  4. Observe a scrollable-region-focusable violation reported on .euiSelectableList__list

Expected behavior

No scrollable-region-focusable violation. Either:

  • The non-virtualized scroll wrapper receives data-skip-axe="scrollable-region-focusable" for consistency with the virtualized path, or
  • The scroll wrapper is made genuinely keyboard-accessible by adding tabIndex={0} and an aria-label derived from the parent EuiSelectable's label or a new dedicated prop.

Screenshots (Optional)

Axe violation output from our Playwright a11y test:

Rule: scrollable-region-focusable. Impact: (serious)
Description: Ensure elements that have scrollable content are accessible by keyboard
Help: Scrollable region must have keyboard access
Nodes: 1. Selectors: .euiSelectableList__list

Additional context (Optional)

Relevant source locations:

  • Scrollable styles applied: selectable_list.styles.ts:42–49 (euiYScrollWithShadows)
  • tabindex="-1" assignment: selectable_list.tsx:222–228 (removeScrollableTabStop)
  • Virtualized path axe skip (existing fix): selectable_list.tsx:522
  • Non-virtualized render (missing fix): selectable_list.tsx:753–759

Metadata

Metadata

Assignees

No one assigned

    Type

    No fields configured for Bug.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions