[EuiSuperSelect] Dropdown stays open when Tab leaves the control (all options disabled)
- Dominant language
- TypeScript
- Stars
- 6.4k
- Forks
- 911
- Avg merge
- 2d 11h
- Merged PRs (30d)
- 65
Description
**Reported by**
Kibana accessibility audit — [elastic/kibana#276916](https://github.com/elastic/kibana/issues/276916)
**Describe the bug**
`EuiSuperSelect` leaves its dropdown open when keyboard focus leaves the collapsed control. This is most reproducible when **every option is disabled**: opening via keyboard never lands focus inside the listbox, so `Tab` moves to the next element while the overlay stays behind (WCAG SC 1.4.13).
This is not unique to one Kibana screen. Any SuperSelect whose options are all `disabled` (or any open state where focus never enters the list) has the same failure.
Two implementation issues in current `main` (`packages/eui/src/components/form/super_select/super_select.tsx`):
1. **`openPopover` cannot focus a disabled item.** It walks past disabled options, then falls back to a disabled index and calls `.focus()` on that button. Disabled buttons cannot take focus, so focus stays on the toggle. The listbox has `tabIndex={0}` but is never focused.
2. **`closePopover` always restores focus to the toggle.** That is correct for Escape / click-outside / selection, but wrong when the user has already tabbed away. Consumers cannot work around this: `isOpen={isOpen || state.isPopoverOpen}` cannot force-close, so the only consumer-side dismiss is remounting the component.
Tab-to-close only exists on **items** (`onItemKeyDown` selects + closes). `EuiInputPopover`’s tab handler only runs for Tab **inside the panel**. The control has no blur/Tab close, and SuperSelect sets `disableFocusTrap`, so focus can leave while the overlay stays.
**Impact and severity**
Keyboard users (and anyone tabbing through a form) can leave a stale overlay covering the next field. Kibana hit this on Synthetics → Settings → Private locations → **Agent policy** when every policy is already used (all options disabled). We considered a remount-on-blur workaround in Kibana ([PR #277692](https://github.com/elastic/kibana/pull/277692)) and are **not** landing it — this belongs in EUI so every SuperSelect is fixed.
No good consumer workaround: calling `closePopover` yanks focus back to the control.
**Environment and versions**
- EUI version: `118.0.0` (Kibana) — same `openPopover` / `closePopover` logic is still on `elastic/eui` `main`
- Kibana version: 9.5.0
- Browser: Chrome
- OS: macOS
**Minimum reproducible sandbox**
Repro on https://eui.elastic.co/docs/components/forms/selection/super-select (or any SuperSelect playground) by making **all** options `disabled`:
```tsx
import React, { useState } from 'react';
import { EuiSuperSelect } from '@elastic/eui';
export default () => {
const options = [
{ value: 'one', inputDisplay: 'Option one', disabled: true },
{ value: 'two', inputDisplay: 'Option two', disabled: true },
];
const [value, setValue] = useState();
return (
<>
Next field
);
};
```
**To Reproduce**
1. Render `EuiSuperSelect` with every option `disabled: true`.
2. Keyboard-focus the control.
3. Press `ArrowDown` (or `Space`) to open the list.
4. Press `Tab`.
5. Focus moves to the next element; the dropdown stays open.
**Expected behavior**
The dropdown closes when focus leaves the component, without moving focus back to the toggle. Native `` dismisses on Tab-away.
Suggested EUI fix (small):
- Split `closePopover` so restore-focus is optional (`closePopover({ restoreFocus })`), and skip restore when focus has already left.
- Handle `Tab` on the **control** while the popover is open: close without restoring focus.
- If no enabled option exists: do not open, or focus the listbox so panel tab-to-close can run (still needs `restoreFocus: false`, or `handleTabNavigation` → `closePopover` will steal focus back).
**Screenshots (Optional)**
Recording from the Kibana a11y report: https://github.com/user-attachments/assets/8814602b-29ce-41f8-b886-a85d6e785b8f
**Additional context (Optional)**
- Kibana issue: https://github.com/elastic/kibana/issues/276916
- Rejected Kibana workaround PR: https://github.com/elastic/kibana/pull/277692
- Related a11y: [WCAG 2.2 SC 1.4.13 Content on Hover or Focus](https://www.w3.org/WAI/WCAG22/Understanding/content-on-hover-or-focus.html)
- Prior SuperSelect focus work: https://github.com/elastic/eui/pull/7650 (did not cover the all-disabled / focus-never-enters-list case)
Contributor guide
Research direction
Start in packages/eui/src/components/form/super_select/super_select.tsx and reproduce the all-disabled case from the issue or the SuperSelect documentation playground. Trace openPopover, closePopover, the control key handling, and the panel Tab handling; done means Tab-away closes the dropdown while preserving focus on the next element, including when no option can receive focus.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- react, typescript
- Domain
- accessibility, frontend
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 72/100