Events
DockviewApi exposes a comprehensive set of events so your application can react to layout changes. All events follow the same subscription pattern and return a disposable that you should call when you no longer need the listener.
const disposable = api.onDidAddPanel((panel) => {
console.log('panel added:', panel.id);
});
// later, when cleaning up:
disposable.dispose();
Panel Lifecycle
These events fire when panels are added, removed, moved, or change active state.
// Fires when a panel is added (including when panels move between groups)
api.onDidAddPanel((panel: IDockviewPanel) => { });
// Fires when a panel is removed (including when panels move between groups)
api.onDidRemovePanel((panel: IDockviewPanel) => { });
// Fires when the active panel changes. `panel` may be undefined if no panel is
// active. `origin` is 'user' for a user gesture (e.g. clicking a tab) or 'api'
// for a programmatic `setActive` call.
api.onDidActivePanelChange((event: DockviewActivePanelChangeEvent) => {
// event.panel: IDockviewPanel | undefined
// event.origin: 'user' | 'api'
});
// Fires when a panel moves from one group to another
api.onDidMovePanel((event: MovePanelEvent) => { });
onDidAddPanel and onDidRemovePanel fire during panel moves. A panel being moved from group A to group B will trigger a remove followed by an add. Use onDidMovePanel if you only want to react to explicit moves.
Group Lifecycle
These events fire when groups are added, removed, or change active state.
// Fires when a group is added (including during moves)
api.onDidAddGroup((group: DockviewGroupPanel) => { });
// Fires when a group is removed (including during moves)
api.onDidRemoveGroup((group: DockviewGroupPanel) => { });
// Fires when the active group changes. May be undefined if no group is active.
api.onDidActiveGroupChange((group: DockviewGroupPanel | undefined) => { });
Layout
These events fire when the overall layout structure changes.
// Fires on any layout change (aggregation of many events).
// Consider debouncing if using for persistence.
api.onDidLayoutChange(() => { });
// Fires after a layout is loaded via api.fromJSON()
api.onDidLayoutFromJSON(() => { });
// Fires when a group is maximized or un-maximized
api.onDidMaximizedGroupChange((event: DockviewMaximizedGroupChangeEvent) => { });
Mutation boundary
onWillMutateLayout and onDidMutateLayout bracket each top-level structural change to the layout. Unlike onDidLayoutChange — which is coalesced and only fires after a change — these provide an explicit before/after pair, so you can capture a snapshot of the layout before the mutation runs. This makes them the right hook for autosave, dirty-tracking and undo/redo.
// Fires immediately before a structural mutation
api.onWillMutateLayout((event: DockviewLayoutMutationEvent) => {
// event.kind: 'add' | 'remove' | 'move' | 'float' | 'popout'
// | 'tab-group' | 'load' | 'clear'
// event.origin: 'user' | 'api'
const snapshot = api.toJSON(); // pre-image, before the change applies
});
// Fires immediately after the same mutation settles
api.onDidMutateLayout((event: DockviewLayoutMutationEvent) => { });
A compound operation brackets as a single transaction: dragging a panel to a new group, or restoring a whole layout via fromJSON, fires exactly one before/after pair rather than one per internal step.
event.origin distinguishes who caused the change — 'user' for direct interaction (drag-and-drop, tab UI), 'api' for a programmatic DockviewApi call made by your own code — so consumers such as an undo stack can choose to ignore the app's own programmatic mutations.
Drag & Drop
These events let you intercept and customize drag and drop behaviour.
// Fires before dockview handles a drop. Call event.preventDefault() to cancel it.
api.onWillDrop((event: DockviewWillDropEvent) => {
// event.preventDefault() to cancel the drop
});
// Fires when a drop completes that dockview handled
api.onDidDrop((event: DockviewDidDropEvent) => { });
// Fires before a drop overlay is shown. Call event.preventDefault() to prevent it.
api.onWillShowOverlay((event: DockviewWillShowOverlayLocationEvent) => {
// event.preventDefault() to hide the overlay for this position
});
// Fires before a panel tab drag begins. Call event.nativeEvent.preventDefault() to cancel.
api.onWillDragPanel((event: TabDragEvent) => { });
// Fires before a group header drag begins. Call event.nativeEvent.preventDefault() to cancel.
api.onWillDragGroup((event: GroupDragEvent) => { });
// Fires for drag-over events that dockview did not originate.
// Call event.accept() to let dockview show a drop overlay for external drags.
api.onUnhandledDragOver((event: DockviewDndOverlayEvent) => {
event.accept();
});
See Drag & Drop and External Dnd Events for full examples.
Popout Window
These events fire in response to popout window activity.
// Fires when a popout group opens in its own window, carrying the live Window
// handle. Use it to route focus or attach listeners to the popout's document.
api.onDidAddPopoutGroup((event: PopoutGroup) => {
// event.id, event.group, event.window
event.window.focus();
});
// Fires when a popout group is removed — the user closed its window or it was
// docked back programmatically. Not fired during component disposal.
api.onDidRemovePopoutGroup((event: PopoutGroup) => {
// event.id, event.group
});
// Fires when a popout window is resized
api.onDidPopoutGroupSizeChange((event: PopoutGroupChangeSizeEvent) => { });
// Fires when a popout window is repositioned
api.onDidPopoutGroupPositionChange((event: PopoutGroupChangePositionEvent) => { });
// Fires when the browser blocked opening a popout window (e.g. popup blocker)
api.onDidOpenPopoutWindowFail(() => {
console.warn('popup was blocked by the browser');
});
Enumerate the popout groups currently open at any time:
for (const popout of api.getPopouts()) {
// popout.id, popout.group, popout.window
}
See Popout Windows for more.
Tab Groups
These events fire when tab groups are created, destroyed, or modified across any group.
// Fires when a tab group is created
api.onDidCreateTabGroup((event: DockviewTabGroupChangeEvent) => {
console.log('tab group created:', event.tabGroup.id);
});
// Fires when a tab group is destroyed (including auto-destroy when emptied)
api.onDidDestroyTabGroup((event: DockviewTabGroupChangeEvent) => { });
// Fires when a panel is added to a tab group
api.onDidAddPanelToTabGroup((event: DockviewTabGroupPanelChangeEvent) => {
console.log(`panel ${event.panelId} added to group ${event.tabGroup.id}`);
});
// Fires when a panel is removed from a tab group
api.onDidRemovePanelFromTabGroup((event: DockviewTabGroupPanelChangeEvent) => { });
// Fires when a tab group's properties change (label, color)
api.onDidTabGroupChange((event: DockviewTabGroupChangeEvent) => { });
// Fires when a tab group is collapsed or expanded
api.onDidTabGroupCollapsedChange((event: DockviewTabGroupCollapsedChangeEvent) => {
console.log(event.tabGroup.id, event.tabGroup.collapsed ? 'collapsed' : 'expanded');
});
See Tab Groups for the full API.
Panel API Events
Individual panels also expose events via panel.api:
// Fires when the panel's title changes
panel.api.onDidTitleChange(({ title }) => { });
// Fires when the panel becomes visible or hidden
panel.api.onDidVisibilityChange(({ isVisible }) => { });
// Fires when the panel moves to a different group
panel.api.onDidGroupChange(() => { });
// Fires when the panel's group active state changes
panel.api.onDidActiveGroupChange(({ isActive }) => { });
// Fires when the panel's location changes (grid → floating → popout)
panel.api.onDidLocationChange(({ location }) => { });
// Fires when the panel's renderer mode changes
panel.api.onDidRendererChange(({ renderer }) => { });
Group API Events
Groups expose events via group.api:
// Fires when the active panel within this group changes
group.api.onDidActivePanelChange((event) => {
// event.panel: IDockviewPanel
// event.origin: 'user' | 'api'
});
// Fires when the group location changes (grid → floating → popout)
group.api.onDidLocationChange(({ location }) => { });
There are two onDidActivePanelChange events that differ in scope:
api.onDidActivePanelChange(DockviewActivePanelChangeEvent) tracks the active panel across the whole dockview;panelmay beundefined.group.api.onDidActivePanelChange(DockviewGroupActivePanelChangeEvent) is scoped to a single group.
Both carry an origin ('user' | 'api') reporting whether the change came from a user gesture or an API call.