Description
When using Combobox.Chips / Combobox.ChipsInput (instead of Combobox.Input), the body gets overflow: hidden on mount even when modal={false} is set on the Root.
Using Combobox.Input with the same configuration does not exhibit this behavior.
Minimal reproduction
"use client";
import { Combobox } from "@base-ui/react/combobox";
export default function Repro() {
return (
<div style={{ height: "200vh", padding: 20 }}>
<h1>Scroll test</h1>
<Combobox.Root multiple modal={false}>
<Combobox.Chips>
<Combobox.ChipsInput placeholder="Type here..." />
</Combobox.Chips>
<Combobox.Portal>
<Combobox.Positioner>
<Combobox.Popup>
<Combobox.List>
<Combobox.Item value="a">Alpha</Combobox.Item>
</Combobox.List>
</Combobox.Popup>
</Combobox.Positioner>
</Combobox.Portal>
</Combobox.Root>
<div style={{ height: "100vh", background: "#eee", marginTop: 20 }}>
You should be able to scroll to see this.
</div>
</div>
);
}
Expected behavior
Page should be scrollable. modal={false} should prevent scroll locking.
Actual behavior
document.body gets style="overflow: hidden;" on mount, preventing all page scrolling.
Root cause analysis
The ComboboxPositioner passes open && modal && openMethod !== 'touch' to useScrollLock(). When using Combobox.Chips/ChipsInput, the store's open value is undefined on initial render (rather than false as with Combobox.Input).
The && chain undefined && false evaluates to undefined (not false). The useScrollLock function signature is:
function useScrollLock(enabled = true, referenceElement = null)
Since undefined triggers the default parameter, enabled becomes true, and the scroll lock is acquired on mount.
Workaround
Setting defaultOpen={false} on the Root forces the store to initialize open as false:
<Combobox.Root multiple modal={false} defaultOpen={false}>
Possible fixes
- Initialize the combobox store's
open to false when using Chips (same as Input path)
- Coerce the expression in ComboboxPositioner:
useScrollLock(!!(open && modal && openMethod !== 'touch'), triggerElement)
- Change
useScrollLock signature to not use a default parameter: function useScrollLock(enabled, ...) { if (!enabled) return; ... }
Environment
@base-ui/react: 1.3.0
next: 16.2.2
react: 19.2.4
- macOS (overlay scrollbars)
Description
When using
Combobox.Chips/Combobox.ChipsInput(instead ofCombobox.Input), the body getsoverflow: hiddenon mount even whenmodal={false}is set on the Root.Using
Combobox.Inputwith the same configuration does not exhibit this behavior.Minimal reproduction
Expected behavior
Page should be scrollable.
modal={false}should prevent scroll locking.Actual behavior
document.bodygetsstyle="overflow: hidden;"on mount, preventing all page scrolling.Root cause analysis
The
ComboboxPositionerpassesopen && modal && openMethod !== 'touch'touseScrollLock(). When usingCombobox.Chips/ChipsInput, the store'sopenvalue isundefinedon initial render (rather thanfalseas withCombobox.Input).The
&&chainundefined && falseevaluates toundefined(notfalse). TheuseScrollLockfunction signature is:Since
undefinedtriggers the default parameter,enabledbecomestrue, and the scroll lock is acquired on mount.Workaround
Setting
defaultOpen={false}on the Root forces the store to initializeopenasfalse:Possible fixes
opentofalsewhen using Chips (same as Input path)useScrollLock(!!(open && modal && openMethod !== 'touch'), triggerElement)useScrollLocksignature to not use a default parameter:function useScrollLock(enabled, ...) { if (!enabled) return; ... }Environment
@base-ui/react: 1.3.0next: 16.2.2react: 19.2.4