[combobox] Hidden input styles in combobox interferes with dnd operations
Hidden input with position: fixed interferes with drag-and-drop operations
Description
The Combobox component creates a hidden input element with position: fixed; top: 0px; left: 0px; for form integration and accessibility. When the Combobox is used inside draggable elements (e.g., with @atlaskit/pragmatic-drag-and-drop or similar libraries), this fixed positioning causes the hidden input to be positioned at the viewport corner, which interferes with drag-and-drop operations and affects the drag preview.
Environment
-
Base UI Version:
@base-ui-components/react(latest) - React Version: 18.x
- Browser: Chrome/Firefox/Safari (all affected)
Reproduction
- Create a Combobox component inside a draggable container
- Implement drag-and-drop using any DnD library (e.g.,
@atlaskit/pragmatic-drag-and-drop,react-dnd, etc.) - Attempt to drag the container
- Observe that the hidden input element at the top-left corner of the viewport interferes with the drag operation
Code Example
import { Combobox } from '@base-ui-components/react/combobox';
import { draggable } from '@atlaskit/pragmatic-drag-and-drop/element/adapter';
function DraggableCombobox() {
const ref = useRef(null);
useEffect(() => {
const element = ref.current;
if (!element) return;
return draggable({
element,
getInitialData: () => ({ id: 'item-1' }),
});
}, []);
return (
<div ref={ref}>
<Combobox.Root value="option1">
<Combobox.Trigger>Select option</Combobox.Trigger>
<Combobox.Portal>
<Combobox.Positioner>
<Combobox.Popup>
{/* ... */}
</Combobox.Popup>
</Combobox.Positioner>
</Combobox.Portal>
</Combobox.Root>
</div>
);
}
Expected Behavior
The hidden input should be positioned relative to its parent container (using position: absolute) so it doesn't interfere with drag-and-drop operations or appear outside the component's bounds.
Actual Behavior
The hidden input is created with inline styles:
<input
id="base-ui-:r2f:"
tabindex="-1"
aria-hidden="true"
value="CLOSED"
style="clip: rect(0px, 0px, 0px, 0px); overflow: hidden; white-space: nowrap; position: fixed; top: 0px; left: 0px; border: 0px; padding: 0px; width: 1px; height: 1px; margin: -1px;"
>
The position: fixed; top: 0px; left: 0px; positions the input at the viewport corner, which:
- Interferes with drag-and-drop calculations
- Can affect the drag preview generation
- May capture unintended pointer events in some scenarios
Suggested Solution
Change the hidden input's positioning from fixed to absolute to keep it within its parent's bounds:
- style="position: fixed; top: 0px; left: 0px; ..."
+ style="position: absolute; top: 0px; left: 0px; ..."
This maintains the same visual hiding effect while keeping the element scoped to its container, preventing interference with drag-and-drop operations.
Workaround
Currently using the inputRef prop to manually override the positioning:
const hiddenInputRef = useRef<HTMLInputElement>(null);
useEffect(() => {
const node = hiddenInputRef.current;
if (node) {
node.style.position = 'absolute';
node.style.pointerEvents = 'none';
}
}, []);
<Combobox.Root inputRef={hiddenInputRef}>
{/* ... */}
</Combobox.Root>
Additional Context
This issue affects any use case where Combobox is used within draggable UI elements, which is common in:
- Kanban boards
- Sortable lists
- Draggable cards/panels
- Dynamic layouts with DnD
The hidden input serves an important purpose for accessibility and form integration, so it should remain in the DOM—just with positioning that doesn't interfere with parent element interactions.
contain: layout CSS on that container div will scope the fixed hidden input element to it, which is the same as position: absolute
@atomiks Yes, this makes sense. Should I close this issue?
Almost a year ago, the style was changed from position: absolute to position: fixed: https://github.com/mui/base-ui/pull/1077.
@atomiks @michaldudak Do you think it makes sense to change a utility behavior to fix an issue in the docs? 🤔
For context, Material UI uses position: absolute: https://github.com/mui/material-ui/blob/master/packages/mui-utils/src/visuallyHidden/visuallyHidden.ts