Bug report
Current behavior
A disabled Toolbar.Input still accepts text entered through an IME (Korean, Japanese, Chinese, etc.). Typing with a Latin keyboard is correctly blocked, but composing text with an IME writes into the input as if it were enabled.
The root cause is in useFocusableWhenDisabled, which blocks text entry solely by cancelling keydown:
https://github.com/mui/base-ui/blob/master/packages/react/src/utils/useFocusableWhenDisabled.ts#L22-L24
onKeyDown(event: React.KeyboardEvent) {
if (disabled && focusableWhenDisabled && event.key !== 'Tab') {
event.preventDefault();
}
}
Toolbar.Input passes focusableWhenDisabled (default true) and isNativeButton: false, so the native disabled attribute is never applied — only aria-disabled. The repo's own test asserts this (ToolbarInput.test.tsx: expect(input).not.toHaveAttribute('disabled')). ToolbarInput itself only cancels onClick and onPointerDown, so that single preventDefault is the only thing preventing text entry.
That is not enough: an IME commits composed text through a channel that keydown cancellation never reaches.
Importantly, preventDefault is not failing to run. I measured it being called, and it does correctly block both ordinary typing and text carried on the key event itself. Only the composition → commit path gets through.
Measurements
Chromium, driven over CDP with Input.dispatchKeyEvent (virtual keycode 229, as a real IME emits) followed by Input.imeSetComposition + Input.insertText. Each variant is a bare <input>; prevented reproduces useFocusableWhenDisabled's handler verbatim.
| variant |
IME (compose after cancelled keydown) |
text on key event |
ordinary typing |
| control (no handler) |
한 |
한 |
abc |
| prevented (current behavior) |
한 ← bug |
'' |
'' |
native disabled attribute |
'' |
'' |
'' |
readOnly |
'' |
'' |
'' |
The control row confirms the simulation is faithful; the prevented row is the bug.
Expected behavior
A disabled Toolbar.Input should not accept text from any input method, including IME composition.
Reproducible example
Render a disabled Toolbar.Input, focus it, and type with an IME (e.g. Korean 2-set):
<Toolbar.Root>
<Toolbar.Input disabled defaultValue="" />
</Toolbar.Root>
The composed characters appear in the input.
Standalone script reproducing the mechanism headlessly (no React needed, ~1s, exits non-zero on the bug) — happy to open it as a gist or fold it into a test if useful.
Base UI version
v1.6.0
Which browser are you using?
Chrome (measured). Not yet verified in Safari or Firefox — worth checking, since NumberFieldInput already notes that isComposing is broken in Safari (webkit bug 165004).
Which OS are you using?
macOS
Which assistive tech are you using (if applicable)?
N/A
Additional context
Suggested fix
Marking the input readOnly while disabled blocks every path above while keeping the element focusable, so focusableWhenDisabled behavior (tabbing away, roving focus) is preserved. The native disabled attribute also blocks IME but removes focusability, defeating the purpose of the hook.
Scoping it to ToolbarInput looks sufficient: useFocusableWhenDisabled has only two consumers (ToolbarInput and useButton), and isNativeButton: false is only used by ToolbarInput — it is the only text-entry consumer. Applying readOnly in the shared hook would leak the attribute onto buttons and links.
As a bonus, readOnly also closes context-menu paste, drag-and-drop, and autofill, which currently bypass the disabled state through the same gap.
Note that readOnly is ignored by checkboxes, so Toolbar.Input type="checkbox" would keep relying on the existing onClick/onPointerDown handling — not an IME concern.
Relationship to #4968
#4968 states: "Removed the redundant stopEvent keydown handler from Toolbar.Input… useFocusableWhenDisabled already prevents text entry." This report contradicts that premise for IME input, so the fix would partially revisit that decision. Flagging it explicitly so the history is clear.
Why the existing keyCode === 229 guards don't apply
The repo has event.which === 229 guards in NumberFieldInput, ComboboxInput, and useListNavigation, but those exist to avoid interfering with IME composition — the opposite of what's needed here. Adding such a guard makes no difference to this bug; the composition commit path still writes to the input.
Test coverage gap
ToolbarInput.test.tsx currently contains no keyDown, preventDefault, or composition assertions, so "typing is blocked while disabled" is untested in general, not just for IME.
Bug report
Current behavior
A disabled
Toolbar.Inputstill accepts text entered through an IME (Korean, Japanese, Chinese, etc.). Typing with a Latin keyboard is correctly blocked, but composing text with an IME writes into the input as if it were enabled.The root cause is in
useFocusableWhenDisabled, which blocks text entry solely by cancellingkeydown:https://github.com/mui/base-ui/blob/master/packages/react/src/utils/useFocusableWhenDisabled.ts#L22-L24
Toolbar.InputpassesfocusableWhenDisabled(defaulttrue) andisNativeButton: false, so the nativedisabledattribute is never applied — onlyaria-disabled. The repo's own test asserts this (ToolbarInput.test.tsx:expect(input).not.toHaveAttribute('disabled')).ToolbarInputitself only cancelsonClickandonPointerDown, so that singlepreventDefaultis the only thing preventing text entry.That is not enough: an IME commits composed text through a channel that
keydowncancellation never reaches.Importantly,
preventDefaultis not failing to run. I measured it being called, and it does correctly block both ordinary typing and text carried on the key event itself. Only the composition → commit path gets through.Measurements
Chromium, driven over CDP with
Input.dispatchKeyEvent(virtual keycode 229, as a real IME emits) followed byInput.imeSetComposition+Input.insertText. Each variant is a bare<input>;preventedreproducesuseFocusableWhenDisabled's handler verbatim.한한abc한← bug''''disabledattribute''''''readOnly''''''The
controlrow confirms the simulation is faithful; thepreventedrow is the bug.Expected behavior
A disabled
Toolbar.Inputshould not accept text from any input method, including IME composition.Reproducible example
Render a disabled
Toolbar.Input, focus it, and type with an IME (e.g. Korean 2-set):The composed characters appear in the input.
Standalone script reproducing the mechanism headlessly (no React needed, ~1s, exits non-zero on the bug) — happy to open it as a gist or fold it into a test if useful.
Base UI version
v1.6.0
Which browser are you using?
Chrome (measured). Not yet verified in Safari or Firefox — worth checking, since
NumberFieldInputalready notes thatisComposingis broken in Safari (webkit bug 165004).Which OS are you using?
macOS
Which assistive tech are you using (if applicable)?
N/A
Additional context
Suggested fix
Marking the input
readOnlywhile disabled blocks every path above while keeping the element focusable, sofocusableWhenDisabledbehavior (tabbing away, roving focus) is preserved. The nativedisabledattribute also blocks IME but removes focusability, defeating the purpose of the hook.Scoping it to
ToolbarInputlooks sufficient:useFocusableWhenDisabledhas only two consumers (ToolbarInputanduseButton), andisNativeButton: falseis only used byToolbarInput— it is the only text-entry consumer. ApplyingreadOnlyin the shared hook would leak the attribute onto buttons and links.As a bonus,
readOnlyalso closes context-menu paste, drag-and-drop, and autofill, which currently bypass the disabled state through the same gap.Note that
readOnlyis ignored by checkboxes, soToolbar.Input type="checkbox"would keep relying on the existingonClick/onPointerDownhandling — not an IME concern.Relationship to #4968
#4968 states: "Removed the redundant
stopEventkeydown handler fromToolbar.Input…useFocusableWhenDisabledalready prevents text entry." This report contradicts that premise for IME input, so the fix would partially revisit that decision. Flagging it explicitly so the history is clear.Why the existing
keyCode === 229guards don't applyThe repo has
event.which === 229guards inNumberFieldInput,ComboboxInput, anduseListNavigation, but those exist to avoid interfering with IME composition — the opposite of what's needed here. Adding such a guard makes no difference to this bug; the composition commit path still writes to the input.Test coverage gap
ToolbarInput.test.tsxcurrently contains nokeyDown,preventDefault, orcompositionassertions, so "typing is blocked while disabled" is untested in general, not just for IME.