[EuiSelectableList] `scrollable-region-focusable` axe violation in non-virtualized mode
- Dominant language
- TypeScript
- Stars
- 6.4k
- Forks
- 911
- Avg merge
- 2d 11h
- Merged PRs (30d)
- 65
Description
**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 `
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`
Contributor guide
Assessment
This issue has not been assessed yet.