Popout windows
Popout groups open a group in a separate native browser window while it stays part of the same Dockview layout, useful for spreading panels across multiple monitors. The group can be docked back into the grid at any time.
Popout groups cannot be maximized. Calling maximize function on groups in these states will have no effect.
addPopoutGroup | Add a popout group in a new Window
|
|---|
Dockview has built-in support for opening groups in new windows. Each popout window hosts its own nested layout, so you can dock multiple groups together inside a single popout window, and you can have as many popout windows as needed.
The popout lifecycle is observable: onDidAddPopoutGroup /
onDidRemovePopoutGroup fire as windows open and close (or dock back), and
api.getPopouts() enumerates the open popout windows. See
Events.
Popout windows require your website to have a blank .html page that can be used, by default this is set to /popout.html but
can be configured to match requirements.
api.addPopoutGroup(
group,
// the second arguments (options) is optional
{
popoutUrl: '/popout.html',
box: { left: 0, top: 0, height: 200, width: 300 },
}
);
If you do not provide
options.popoutUrla default of/popout.htmlis used and ifoptions.boxis not provided the panel will be placed according to its current position.
popoutUrl must point to a same-origin location: the same scheme and host as the page, which includes an app's own scheme in a desktop webview (for example tauri://localhost). Dockview rejects javascript:, data:, blob:, vbscript:, file: and cross-origin URLs to prevent a malicious value (for example, from a layout JSON loaded from an untrusted source) from executing script in a context the browser still associates with your application via window.opener. The guard runs automatically when the popout is opened, including on layouts restored via fromJSON().
To check a URL yourself - to disable a "pop out" affordance, or to report why it was refused - call getPopoutUrlError(url), the same guard Dockview applies. It returns the Error it would have raised, or undefined when the URL is allowed.
From within a panel you may say
props.containerApi.addPopoutGroup(props.api.group);
Awaiting the open
addPopoutGroup is asynchronous. The window opens first and the group is only
moved into it once that has happened, so await the call when the next step
depends on the group already being there.
const opened = await api.addPopoutGroup(group);
if (!opened) {
// the popout was not created and the group is still in the main grid
}
The promise always settles, and resolves false instead of throwing when the
popout could not be created: the browser blocked the window, the window was
closed before it finished loading, or the item cannot be popped out at all (an
edge group). The panels are left in the main grid, or returned to the group they
came from, and onDidOpenPopoutWindowFail fires for a window that never became
usable, carrying which way it failed: 'blocked', 'url-refused',
'unscriptable' or 'closed'.
The layout transaction covers the whole
operation: onWillMutateLayout fires with kind: 'popout' before the window is
opened, and the matching onDidMutateLayout only once the promise settles, so
the panel moves the popout makes are bracketed by the pair rather than landing
after it.
Closing the popout group
To programmatically move the popout group back into the main grid you can use the moveTo method in many ways, one of the following would suffice
// option 1: add absolutely to the right-side of the grid
props.group.api.moveTo({ position: 'right' });
// option 2: create a new group and move the contents of the popout group to it
const group = props.containerApi.addGroup();
props.group.api.moveTo({ group });
Alternatively, if the user closes the window the group Dockview will make a best attempt to place it back in its original location within the grid. If Dockview cannot determine the original location it will choose a new location.
Overlays inside popout windows
Floating overlays, including drag-target indicators, the tab context menu, and tab group chip popovers (color picker, rename), render inside the DOM of the window that hosts them. When a group lives in a popout window, those overlays render in the popout window's document, not the parent. This means:
- Custom chip components and context menu components are mounted in the popout window's DOM tree.
- CSS that you load into the main page is automatically copied into popout windows; if you ship custom styles outside the standard import pipeline (for example, lazily injected stylesheets), make sure they are also available in the popout window.
- Event handlers and portals inside custom components should not assume the document is the main window; use the element's
ownerDocumentwhen you need a reference.
Popout window events
DockviewApi exposes four events specific to popout windows:
// Fires when the popout window is resized by the user
api.onDidPopoutGroupSizeChange((event: PopoutGroupChangeSizeEvent) => {
console.log('popout resized:', event);
});
// Fires when the popout window is moved by the user
api.onDidPopoutGroupPositionChange((event: PopoutGroupChangePositionEvent) => {
console.log('popout moved:', event);
});
// Fires when a popout window could not be used, saying which way it failed
api.onDidOpenPopoutWindowFail((failure) => {
if (failure.reason === 'blocked') {
alert('Please allow popups for this site to use this feature.');
}
});
// Fires as Dockview lets go of a popout window, while the window is still open
api.onWillClosePopoutWindow((event) => {
console.log('closing', event.id, event.window);
});
onWillClosePopoutWindow fires for every popout window the component opened,
however it was opened, and whatever is closing it - component disposal included.
The per-call onDidOpen / onWillClose options on addPopoutGroup only see the
popout that call opened, so they miss the ones Dockview opens for itself: from
the group context menu, or when restoring a saved layout.
That matters when the host owns its windows rather than the browser. In a
desktop webview (Tauri, Electron and friends), the page's own window.close()
may not close the real window, so the shell has to be asked to close it -
onWillClosePopoutWindow hands over the live handle at the one moment that is
still possible. onDidAddPopoutGroup is the opening half of the same pair.
See also
- Floating groups: float a group above the grid without a separate window
- Events: observe the popout window lifecycle
- Security: same-origin requirements and CSP for popout windows