Is your feature request related to a problem? Please describe.
When using Dockview with floatingGroupBounds="boundedWithinViewport" for a floating-first panel layout (similar to Adobe Photoshop or browser-style tab management), two core interactions don't work:
Floating-to-floating tab merge: Dragging a tab from one floating group onto another floating group does not show drop overlays or merge the panels as tabs. The only way to merge is to first dock a panel to the grid, then drag from the grid onto a floating group. Root cause: DragAndDropObserver registers dragenter/dragover with useCapture: true, so the root container's Droptarget processes events in the capture phase before floating group elements. The root marks events via USED_EVENT_ID before floating groups ever see them.
Tear-off to float: Dragging a tab out of a multi-tab floating group always docks it to the grid via moveGroupOrPanel. There is no code path that creates a new floating group from a tear-off. Users expect the torn-off tab to become a new floating panel (like browser tab tear-off), not dock to the background.
Describe the solution you'd like
A configuration option on DockviewReact (or DockviewOptions) that enables floating-first tab behavior:
<DockviewReact
floatingGroupBounds="boundedWithinViewport"
floatingTabBehavior="browser" // new option
// "browser" = floating-to-floating merge works, tear-off creates float
// "default" = current behavior (backward compatible)
/>
Describe alternatives you've considered
We've implemented both behaviors as workarounds using existing public APIs without forking:
Floating merge fix: api.onWillShowOverlay handler — when kind === 'edge' (root overlay) and the mouse is geometrically over a non-source floating group's overlay element, call preventDefault(). This prevents the root from calling markAsUsed() (line 179 of droptarget.js only runs after the defaultPrevented check at line 175), allowing the floating group's Droptarget to process the event normally.
Tear-off to float: api.onWillDrop handler — when kind === 'edge' and the source is a floating tab group with 2+ panels, call preventDefault() then setTimeout(() => api.addFloatingGroup(panel, {x, y, width, height}), 0).
These workarounds are stable and use only public APIs (onWillShowOverlay, onWillDrop, addFloatingGroup, group.api.location.type), but it would be better as a first-class feature so the community benefits and the behavior is maintained upstream.
Additional context
We're building a desktop app (Electron + React + TypeScript) with a floating-first panel layout. Panels open as floating "cards" by default and users expect browser-style tab management — drag to merge, drag to tear off, cards stay floating. This is a common UX pattern in creative tools like Photoshop.
Is your feature request related to a problem? Please describe.
When using Dockview with floatingGroupBounds="boundedWithinViewport" for a floating-first panel layout (similar to Adobe Photoshop or browser-style tab management), two core interactions don't work:
Floating-to-floating tab merge: Dragging a tab from one floating group onto another floating group does not show drop overlays or merge the panels as tabs. The only way to merge is to first dock a panel to the grid, then drag from the grid onto a floating group. Root cause: DragAndDropObserver registers dragenter/dragover with useCapture: true, so the root container's Droptarget processes events in the capture phase before floating group elements. The root marks events via USED_EVENT_ID before floating groups ever see them.
Tear-off to float: Dragging a tab out of a multi-tab floating group always docks it to the grid via moveGroupOrPanel. There is no code path that creates a new floating group from a tear-off. Users expect the torn-off tab to become a new floating panel (like browser tab tear-off), not dock to the background.
Describe the solution you'd like
A configuration option on DockviewReact (or DockviewOptions) that enables floating-first tab behavior:
Describe alternatives you've considered
We've implemented both behaviors as workarounds using existing public APIs without forking:
Floating merge fix: api.onWillShowOverlay handler — when kind === 'edge' (root overlay) and the mouse is geometrically over a non-source floating group's overlay element, call preventDefault(). This prevents the root from calling markAsUsed() (line 179 of droptarget.js only runs after the defaultPrevented check at line 175), allowing the floating group's Droptarget to process the event normally.
Tear-off to float: api.onWillDrop handler — when kind === 'edge' and the source is a floating tab group with 2+ panels, call preventDefault() then setTimeout(() => api.addFloatingGroup(panel, {x, y, width, height}), 0).
These workarounds are stable and use only public APIs (onWillShowOverlay, onWillDrop, addFloatingGroup, group.api.location.type), but it would be better as a first-class feature so the community benefits and the behavior is maintained upstream.
Additional context
We're building a desktop app (Electron + React + TypeScript) with a floating-first panel layout. Panels open as floating "cards" by default and users expect browser-style tab management — drag to merge, drag to tear off, cards stay floating. This is a common UX pattern in creative tools like Photoshop.