elastic / elastic/eui

[EuiFilterButton] EuiFilterButton should not infer aria-expanded from active filters

Open
#9,692 5 comments 0 reactions 0 assignees View on GitHub
accessibility help wanted
Dominant language
TypeScript
Stars
6.4k
Forks
911
Avg merge
2d 11h
Merged PRs (30d)
65

Description

**Reported by**

Originally surfaced from Kibana accessibility issue elastic/kibana#227773.

**Describe the bug**

`EuiFilterButton` treats `hasActiveFilters` as a fallback source for `aria-expanded` when it is rendered as a collapsible chevron button:

```ts
const isExpanded = isCollapsible && (isSelected ?? hasActiveFilters);
```

`hasActiveFilters` is a visual/filter-count state, not the disclosure open state. A closed filter popover can still have active filters, so this can leave the trigger exposed to assistive technology as expanded even when the controlled popover is closed, or cause a missing false-to-true announcement the next time the trigger opens.

**Impact and severity**

This affects screen reader users of filter-popover triggers. The Kibana report notes VoiceOver/Safari missing the expanded-state announcement for the Security > Rules > Benchmarks filter buttons. This is WCAG Name, Role, Value related behavior.

**Environment and versions**

- Kibana version: 9.1.0 in the downstream report
- Browser: Safari 18.5
- Screen reader: VoiceOver
- EUI: current `main` still has the `hasActiveFilters` fallback in `packages/eui/src/components/filter_group/filter_button.tsx`

**Minimum reproducible sandbox**

A minimal component-level case is a collapsible `EuiFilterButton` with active filters but no explicit open state:

```tsx

Status

```

The button receives `aria-expanded` even though no open/closed disclosure state was provided.

**To Reproduce**

1. Render `EuiFilterButton` with `iconType="chevronSingleDown"` and `hasActiveFilters`.
2. Do not pass `isSelected`.
3. Inspect the rendered button.
4. Observe that `aria-expanded` is derived from active-filter state.

**Expected behavior**

For collapsible filter buttons, `aria-expanded` should follow the actual disclosure state supplied through `isSelected`. `hasActiveFilters` should continue to affect only active-filter styling and badge semantics. If `isSelected` is omitted, EUI should not infer a disclosure state from active filters.

**Additional context**

I have a small local patch with focused RTL coverage that changes the computed expanded state to use `isSelected` only for collapsible buttons. Happy to open a PR if this scoping looks right.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.