SvDockManager

A full docking manager built on top of SvDockLayout. It keeps everything the tiled layout does - nested resizable splits, tabbed leaves, drag-to-dock - and adds the three features a real IDE workspace needs:

The whole workspace - tiled main area, floating windows, and autoHide edges - is one serializable DockManagerState you bind. Every gesture is a pure transform (from dock-manager-model), so a full multi-window workspace saves to JSON and restores exactly, and the logic is unit-tested without a browser.

Related: SvDockLayout · SvSplitter · Layout & composite overview

Installation

Add it with the CLI - this drops a ready-to-edit SvDockManager starter into your app:

Prefer to see it first? npx @svgrid/ui try dock-manager opens it in a throwaway sandbox - no project needed.

Or install the package and import it directly. SvDockManager ships free in @svgrid/grid (dependency-free):

import { SvDockManager } from '@svgrid/grid'

Example

Build the initial workspace from the base dockGroup / dockTabs / dockPane helpers, start with empty floating / autoHide, and provide a pane snippet.

Open the live example: Docking manager (Layout)

<script lang="ts">
  import { SvDockManager, dockGroup, dockTabs, dockPane, type DockManagerState } from '@svgrid/grid'

  let workspace = $state<DockManagerState>({
    main: dockGroup('row', [
      dockTabs([dockPane('explorer', 'Explorer')]),
      dockGroup('column', [
        dockTabs([dockPane('editor', 'index.ts'), dockPane('readme', 'README.md')]),
        dockTabs([dockPane('terminal', 'Terminal')]),
      ], [0.7, 0.3]),
    ], [0.22, 0.78]),
    floating: [],
    autoHide: [],
  })
</script>

<div style="height: 520px">
  <SvDockManager bind:workspace>
    {#snippet pane(p)}
      {#if p.id === 'explorer'}<FileTree />{:else}<div>{p.title}</div>{/if}
    {/snippet}
  </SvDockManager>
</div>

The workspace model

DockManagerState has three surfaces, each holding the same DockNode / DockTabs pieces as the base layout:

Field Type Meaning
main DockNode | null The tiled dock area (a group / tabs tree). null when everything has been floated or hidden - a drop placeholder appears.
floating FloatWindow[] Pop-out windows: { id, leaf, x, y, width, height, z }. Each is a single tab-leaf.
autoHide AutoHideEntry[] Collapsed panels: { id, side, leaf, size } on an edge.

Because it is plain data, save and restore it:

localStorage.setItem('ws', JSON.stringify(workspace))
workspace = JSON.parse(localStorage.getItem('ws')!)   // tiled + floating + hidden, all restored

Props

Prop Type Default Description
workspace DockManagerState - The whole workspace. Bindable.
pane Snippet<[DockPane]> - Renders each pane's content, keyed by DockPane.
onChange (workspace: DockManagerState) => void - Notified after any change.
onEvent (event: DockEvent) => void - Granular lifecycle events (see below).
onReady (api: DockManagerApi) => void - Receive the imperative API once, on mount.
minSize number 80 Minimum pane size in px along a split.
reorderEnabled boolean true Allow dragging tabs to reorder within a strip.
headerPosition 'top' | 'bottom' | 'left' | 'right' 'top' Which side of each panel its tab strip sits on (left/right render vertical tabs).
keepAlive boolean false Keep inactive tabs mounted (hidden) so their DOM state (scroll, form input) persists across switches.
hideSingleTab boolean false Hide the tab button on a single-pane leaf (no redundant title bar; the panel actions still show).
allowPopout boolean false Offer the pop-out-to-a-new-window panel action. Off by default; the popout() API still works.
locked boolean false Locked / split mode: a fixed set of resizable panes. Tabs can't be dragged (no reorder / float / dock) and the panel action buttons are hidden - only splitter resize + tab switching remain.

Events

onEvent fires a typed DockEvent for each user action, alongside the whole-state onChange:

type DockEvent =
  | { type: 'activePane'; paneId: string; tabsId: string }
  | { type: 'close'; paneId: string }
  | { type: 'float'; paneId: string }
  | { type: 'popout'; paneId: string }
  | { type: 'autoHide'; paneId: string; side: 'left' | 'right' | 'top' | 'bottom' }
  | { type: 'pin'; paneId: string }
  | { type: 'maximize'; tabsId: string; maximized: boolean }
  | { type: 'window'; windowId: string; action: 'minimize' | 'maximize' | 'close' | 'autoHide' }
  | { type: 'focus'; paneId: string }

The focused panel (last engaged) is highlighted with an accent header; drive it from api.focus(paneId) and listen via the focus event.

Gestures

Drop indicators

While you drag, the target shows live feedback so the outcome is never a surprise:

Dragging a floating window's title bar over the tiled area follows the same rule: drop on a guide chip to redock, or release off it to leave the window floating.

Programmatic control

Every surface transform is exported (all immutable, all returning a new DockManagerState) for toolbars, "reset workspace" buttons, or server-driven layouts:

import {
  floatPane, dockPaneOnto, dockWindowOnto, reorderTab,
  autoHideLeaf, pinAutoHidden, dockManagerClosePane, allManagerPaneIds,
} from '@svgrid/grid'

let seq = 0
const genId = () => `w${seq++}`

workspace = floatPane(workspace, 'terminal', { x: 60, y: 60, width: 360, height: 240 }, genId)
workspace = autoHideLeaf(workspace, leafId, 'left')
workspace = dockManagerClosePane(workspace, 'problems')
const ids = allManagerPaneIds(workspace)

Imperative API

Pass onReady to receive a handle for driving the manager from code (toolbars, menus, keyboard shortcuts):

<script lang="ts">
  import { SvDockManager, type DockManagerApi } from '@svgrid/grid'
  let api: DockManagerApi
</script>

<SvDockManager bind:workspace onReady={(a) => (api = a)}>...</SvDockManager>

<!-- later -->
api.float('terminal')      // pop into a floating window
api.popout('editor')       // pop out to a native browser window
api.autoHide('explorer')   // collapse to its nearest edge
api.maximize(leafId)       // maximize a tiled leaf in place (toggle)
api.close('problems')      // close a pane anywhere
api.getState() / api.setState(s)   // snapshot / restore the whole workspace

Touch

Every gesture is built on pointer events with touch-action: none on the tabs, splitters, window bars and resize handles, so dragging to dock, reorder, resize, move windows and pull out fly-outs all work on touch devices without the browser hijacking the drag to scroll.

Accessibility

SvDockManager inherits the SvDockLayout tab / splitter / panel semantics for every docked area, and adds window-level roles on top:

Headless

Like SvDockLayout, the manager is headless in the data-model form: DockManagerState is the framework-free core, and every surface transform is a pure, immutable function (floatPane, dockPaneOnto, reorderTab, autoHideLeaf, pinAutoHidden, dockManagerClosePane, allManagerPaneIds) unit-tested without a browser. You can compute, migrate, or restore an entire multi-window workspace on the server or in a worker and hand the finished state to the component to render. See Headless editors.

Relationship to SvDockLayout

SvDockManager renders SvDockLayout in "manager mode": the tiled area and each floating window are SvDockLayout instances that delegate their gestures up to the manager, so a single drag can flow across the main area, floating windows and edge strips. Reach for SvDockLayout directly when you only need a tiled, in-place docking layout; reach for SvDockManager when you need floating windows, reordering, or auto-hide.

More examples

Docking: API & events

SvDockManager imperative API (onReady) + event stream (onEvent): a toolbar floats / pops out / maximizes / auto-hides / focuses panes from code, with every action logged live.

Open the live example: Docking: API & events (Layout)

Docking: pop out to a window

SvDockManager allowPopout (off by default): pop a panel out to a real OS window for a second monitor - a live monitoring console where Live log / Metrics keep streaming in the popped-out window, and closing it docks the panel back. Falls back to an in-app floating window when pop-ups are blocked.

Open the live example: Docking: pop out to a window (Layout)

See also

Live examples

  • Docking manager - SvDockManager: SvDockLayout plus floating windows, tab reordering and pinning / auto-hide. Drag a tab into open space to float it, along its strip to reorder, or use the tab buttons to auto-hide (collapse to an edge) and pin back. (Popping out to a native OS window is opt-in - see the pop-out demo.)
  • Docking: API & events - SvDockManager imperative API (onReady) + event stream (onEvent): a toolbar floats / pops out / maximizes / auto-hides / focuses panes from code, with every action logged live.
  • Docking: pop out to a window - SvDockManager allowPopout (off by default): pop a panel out to a real OS window for a second monitor - a live monitoring console where Live log / Metrics keep streaming in the popped-out window, and closing it docks the panel back. Falls back to an in-app floating window when pop-ups are blocked.