mui / mui/base-ui

[Menu] [Select] [Checkbox] [Switch] [RadioItem] provide focusableWhenDisabled

Open
#5,139 4 comments 0 reactions 0 assignees View on GitHub
component: checkbox component: menu component: select component: switch
Dominant language
TypeScript
Stars
10.9k
Forks
543
Avg merge
1d 20h
Merged PRs (30d)
101

Description

# Feature request

## Summary

Expose `focusableWhenDisabled` as a public prop on `Menu.Trigger`, `Select.Trigger`, `Checkbox.Root`, `Switch.Root`, and `Radio.Root` (and any other standalone trigger/input components that currently render with the native `disabled` attribute or `tabIndex={-1}` when disabled).

The mechanism already exists internally - `useFocusableWhenDisabled` is used by `Tab`, `Menu.Item`, and `Select.Item`, where it is hardcoded to `true` because composite items need to remain navigable. We would like the same toggle available on top-level controls, so consumers can opt into the same behavior.

When enabled, the component should render `aria-disabled="true"` instead of the native `disabled` attribute (for native button variants), and keep `tabIndex` at its default value of `0` (for non-native variants like `` in Checkbox/Switch/Radio). Click and keyboard activation should remain blocked by `useButton`, exactly as today.

## Motivation

Browsers skip elements with the native `disabled` attribute entirely in the tab order. This is technically spec-compliant, but it has a real accessibility cost:

- Screen reader users cannot discover disabled controls via keyboard.
- WCAG 4.1.2 (Name, Role, Value) requires that state changes be exposed to assistive technologies. The `disabled` attribute exposes the state - but only if the user can actually focus the element.

The current workaround is to use the `render` prop and strip the `disabled` attribute manually:

```tsx
{
const { disabled: nativeDisabled, ...rest } = props;
return ;
}}
/>
```

This works but is fragile, easy to forget, and requires every consumer to know the internal DOM output. Exposing `focusableWhenDisabled` as an opt-in prop would let teams adopt the modern ARIA practice.

A reasonable API:

```tsx
...

```

Default could stay false to avoid a breaking change.

Thanks for considering.

Contributor guide

Open the contributing guide

Research direction

Start by tracing useFocusableWhenDisabled in Tab, Menu.Item, and Select.Item, then inspect Menu.Trigger, Select.Trigger, Checkbox.Root, Switch.Root, and Radio.Root alongside useButton. Add the opt-in behavior while preserving the current default: native variants should expose aria-disabled, non-native variants should remain focusable, and activation must stay blocked when disabled.

Written by the indexing model from the issue text.

Assessment

Tech stack
react, typescript
Domain
accessibility, frontend
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.