Window Manager
Draggable, resizable floating windows with z-order focus, snapping, minimize/maximize, docks, and persistence.
|
|
| Package |
@vizejs/ui/window-manager |
| Maturity |
stable |
| Own the source |
vize lib pull window-manager |
| Requires |
context, controllable-state |
| Aliases |
floating windows, dock, mdi, desktop windows, taskbar |
| Covers |
WinBox.js, react-rnd, Golden Layout floating windows, macOS window management |
Minimal setup
Use a Vue 3.5+ project with Vue SFC compilation configured (see Vite+ integration).
vp install @vizejs/ui
Add the public import below to <script setup lang="ts">. Components provide behavior without styles; the preview uses optional Paper styles.
import { FloatingWindow, WindowDock, WindowManager } from "@vizejs/ui/window-manager";
Or copy the source into your project with vize lib pull window-manager (see Source Distribution).
Try it
This is the basic example maintained with the component source, using the public package imports. The preview adds the optional Paper styles.
Open the interactive example · Styling these components
Copy the example
<!-- Two draggable, resizable windows with title bars, window controls, and a taskbar dock. -->
<script setup lang="ts">
import { FloatingWindow, WindowDock, WindowManager } from "@vizejs/ui/window-manager";
// The manager is the positioning area for its windows, so it needs a size.
const desktopSize = { blockSize: "24rem", inlineSize: "100%" };
</script>
<template>
<WindowManager :snap-threshold="12" :style="desktopSize">
<FloatingWindow
id="notes"
title="Notes"
:default-rect="{ x: 16, y: 16, width: 280, height: 180 }"
>
<template #default="{ handleProps, minimize, toggleMaximize }">
<div v-bind="handleProps">Notes</div>
<button type="button" @click="minimize">Minimize notes</button>
<button type="button" @click="toggleMaximize">Maximize notes</button>
<p>Drag the title bar or use the arrow keys to move this window.</p>
</template>
</FloatingWindow>
<FloatingWindow
id="calendar"
title="Calendar"
:default-rect="{ x: 320, y: 48, width: 260, height: 200 }"
>
<template #default="{ handleProps, minimize }">
<div v-bind="handleProps">Calendar</div>
<button type="button" @click="minimize">Minimize calendar</button>
<p>Shift with the arrow keys resizes the window.</p>
</template>
</FloatingWindow>
<WindowDock label="Taskbar" />
</WindowManager>
</template>
API
FloatingWindow
Source: src/families/layout/window-manager/floating-window.vue
Props
| Prop |
Type |
Default |
Description |
id (required) |
string |
required |
Stable window id used in the layout. |
title (required) |
string |
required |
Accessible window title, also shown by docks. |
defaultRect |
WindowRect |
{ x: 0, y: 0, width: 320, height: 240 } |
Geometry used until the layout stores one for this window. |
defaultMode |
WindowMode |
"normal" |
Mode used until the layout stores one for this window. |
minWidth |
number |
160 |
Minimum width in CSS pixels. |
minHeight |
number |
96 |
Minimum height in CSS pixels. |
maxWidth |
number |
Infinity |
Maximum width in CSS pixels (also limited by the manager). |
maxHeight |
number |
Infinity |
Maximum height in CSS pixels (also limited by the manager). |
resizable |
boolean |
true |
Render resize handles on every edge and corner. |
Events
| Event |
Payload |
Description |
close |
[] |
Fired when the slot's close action is used. The consumer removes the window. |
modeChange |
[mode: WindowMode] |
Fired when the display mode changes. |
Slots
| Slot |
Slot props |
Description |
default |
FloatingWindowSlotState |
Window chrome and content. Receives state, handle props, and window actions. |
Exposed
| Member |
Type |
Description |
element |
Readonly<ShallowRef<HTMLElement | null>> |
Template ref to the rendered root element. |
state |
— |
|
active |
— |
|
focus |
— |
|
WindowDock
Source: src/families/layout/window-manager/window-dock.vue
Props
| Prop |
Type |
Default |
Description |
label |
string |
"Windows" |
Accessible name of the dock navigation. |
filter |
WindowDockFilter |
"all" |
List every window, or only minimized ones. |
Slots
| Slot |
Slot props |
Description |
default |
WindowDockSlotState |
Custom dock content. Receives the listed window summaries; defaults to one button per window. |
WindowManager
Source: src/families/layout/window-manager/window-manager.vue
Props
| Prop |
Type |
Default |
Description |
layout |
WindowLayout |
undefined |
Controlled layout (v-model:layout). undefined selects uncontrolled behavior, which lets useWindowLayoutPersistence load a stored layout after mount. |
defaultLayout |
WindowLayout |
emptyWindowLayout |
Initial uncontrolled layout. Windows missing from it use their own defaults. |
snapThreshold |
number |
8 |
Distance in CSS pixels at which moving windows snap to edges; 0 disables snapping. |
keyboardStep |
number |
16 |
Pixels moved or resized by one arrow key press on a drag handle. |
baseZIndex |
number |
1 |
z-index of the backmost window; later windows stack above it. |
Events
| Event |
Payload |
Description |
update:layout |
[layout: WindowLayout] |
Fired with the next layout after any move, resize, focus, or mode change. |
Slots
| Slot |
Slot props |
Description |
default |
WindowManagerSlotState |
FloatingWindow and WindowDock children. Receives the active id and window summaries. |
Exposed
| Member |
Type |
Description |
element |
Readonly<ShallowRef<HTMLElement | null>> |
Template ref to the rendered root element. |
layout |
— |
|
activeId |
— |
|
measure |
— |
|
Behavior
Normative state x input -> outcome table for window-manager.vue,
floating-window.vue, and window-dock.vue (@vizejs/ui/window-manager). Rows
are proven by window-manager-model.test.ts, window-manager.test.ts, and
window-manager-ssr.test.ts; compile-only assertions live in
window-manager.types.test-d.ts.
| # |
State |
Input |
Outcome |
Proven by |
| WM1 |
known / unknown bounds |
clamp |
rects stay inside known bounds (pinned top-left when too large); unknown bounds leave them untouched |
clamps rects inside known bounds and leaves unknown bounds untouched |
| WM2 |
moving rect |
snap |
edges within the threshold snap to bounds and neighbour edges; 0 disables snapping |
snaps edges to bounds and neighbours within the threshold |
| WM3 |
rect, delta |
move |
the rect moves, snaps, then clamps |
moves by a delta, then snaps and clamps |
| WM4 |
rect, edge, delta |
resize |
the opposite edge stays fixed and size respects min/max constraints and bounds |
resizes from every edge within constraints and bounds |
| WM5 |
stacking order |
raise |
the window moves to the front (unknown ids append; front stays the same array) |
raises windows to the front of the stacking order |
| WM6 |
stored text |
parse |
valid windows and known order ids survive; malformed input yields undefined |
parses stored layouts and drops malformed entries |
| WM7 |
defaults |
render |
labelled non-modal dialogs use default geometry, later windows stack higher, 8 resize handles render |
renders labelled non-modal windows with default geometry and stacking |
| WM8 |
normal window |
pointer down, drag handle |
the window becomes active and frontmost, moves with the pointer, and stops after pointerup |
pointer focus raises a window and dragging the handle moves it |
| WM9 |
normal window |
resize handle, arrows, Shift+arrows |
resize respects minimums; arrows move and Shift+arrows resize by keyboardStep |
resize handles and keyboard move/resize respect constraints |
| WM10 |
any window |
minimize/maximize/dock/close |
minimized windows are hidden, maximized fill the manager, dock buttons restore/minimize, close emits |
minimize, maximize, restore, close, and dock activation |
| WM11 |
controlled, measured |
drag near an edge |
controlled layouts render as given; moves emit snapped, clamped layouts |
controlled layouts drive geometry and snapping clamps to measured bounds |
| WM12 |
storage |
mount, change |
stored layouts load after mount, changes are written back, malformed data and missing scopes are handled |
persists layouts after mount and ignores malformed storage |
| WM13 |
no provider |
mount window or dock |
stable VIZE_UI_CONTEXT_MISSING: WindowManager diagnostic |
windows and docks outside a manager throw the context diagnostic |
| WM14 |
SSR |
isolated requests, hydrate |
byte-identical geometry/stacking/dock markup; hydration without warnings |
renders byte-identical window geometry, stacking, and dock markup, hydrates windows and dock without mismatch warnings |
| WM15 |
DOM/SSR/Vapor |
compile |
every SFC compiles in every renderer lane |
scripts/check-renderers.ts |
Windows are non-modal role="dialog" regions named by title; the drag
handle is a focusable element spread by the consumer (handleProps) that
advertises its arrow-key shortcuts.