vue-dockable-desktop
v1.2.0
Published
Vue 3 port of react-dockable-desktop — a dockable layout engine with split docking, tabbed groups, floating windows and zero-unmount panel persistence.
Maintainers
Readme
vue-dockable-desktop
A window manager and dockable layout engine for Vue 3. Fluid grid splits, tabbed groups, floating resizable windows, zero-unmount state preservation, side panels and modals, toasts, context menus, per-panel overlays, and internationalisation.
Live demo | Users manual | Design decisions | Parity with the React version
Written as a native Vue library — plugins, composables, v-model, slots — not as a
transliteration of its React sibling. It reads and writes the same serialised layout
format as react-dockable-desktop,
so a layout saved by either library loads in the other.
Versioning. vdd follows its own semver, independently of
react-dockable-desktop: matching the two numbers would be a promise that breaks the first time either library needs a breaking change the other does not. Which rdd release a given version corresponds to is stated per release in CHANGELOG.md — this one tracks rdd 6.3.0 — and feature by feature in docs/PARITY.md.
Install
npm install vue-dockable-desktopRequires Vue 3.4+. No other runtime dependencies. The published package is
vue-dockable-desktop; the public API
is pinned by api-surface.json and covered by 730 tests.
Quick start
// main.ts
import { createApp } from 'vue'
import { createWorkspace } from 'vue-dockable-desktop'
import 'vue-dockable-desktop/styles.css' // required
import App from './App.vue'
import MapPanel from './panels/MapPanel.vue'
import EditorPanel from './panels/EditorPanel.vue'
const workspace = createWorkspace({
panels: {
map: { component: MapPanel, defaultOptions: { title: 'Map' } },
editor: { component: EditorPanel, defaultOptions: { title: 'Editor' } },
},
})
createApp(App).use(workspace).mount('#app')<!-- App.vue -->
<script setup lang="ts">
// Components are imported, not registered globally, so a build only carries the ones it uses.
import { VddDesktop, VddModals, VddSidePanels, VddToasts } from 'vue-dockable-desktop'
</script>
<template>
<div class="app">
<VddDesktop />
<VddModals />
<VddSidePanels />
<VddToasts />
</div>
</template>
<style>
.app { height: 100vh; overflow: hidden; }
</style>createWorkspace() returns a Vue plugin — the same shape as createPinia() or
createRouter() — so app.use(workspace) makes useWorkspace() available anywhere:
import { useWorkspace } from 'vue-dockable-desktop'
const ws = useWorkspace()
// openPanel(instanceId, panelKey, options?) — the id is yours, the key is from `panels`.
ws.openPanel('overview', 'map', { title: 'Overview' })
localStorage.setItem('layout', ws.saveLayout())Features
- Split-docking grid — drag a panel to any zone to split it into rows or columns, or drop it onto a tab strip to group it
- Floating windows — 8-direction resize, maximise, minimise, and corner anchoring with automatic stacking
- Zero-unmount persistence — panel DOM is moved, never destroyed, across docking, floating and tab switching, so maps, WebGL contexts and editors keep their state
- Sidebar and toolbar — primary and secondary sidebars, a declarative toolbar, and per-panel contributions that follow the active panel
- Panel overlay — anchored toolbars and floating widgets inside a single panel
- Overlays — side panels, a modal stack, dirty-close confirmation, and toasts
- Layout serialisation — save and restore the whole workspace as a JSON string
- Theming — built-in skins, light/dark colour schemes, all
--vdd-*CSS variables - i18n and RTL — every string is a message key;
dir="rtl"flips the whole workspace - TypeScript-first — complete types, no separate
@typespackage
Documentation
| | |
|---|---|
| Live demo | Every capability in one application — published from demo/ by GitHub Pages on each push to main |
| docs/manual/ | Users manual — 13 chapters, start with Getting started |
| docs/decisions/ | ADRs — why the Vue design diverges from the React one |
| docs/PARITY.md | Feature-by-feature parity with react-dockable-desktop, and the 16 deliberate divergences |
| docs/IMPLEMENTATION_PLAN.md | The milestone plan and its gates |
| docs/PROGRESS.md | One row per gate run |
| CHANGELOG.md | What has changed, newest first |
Repository layout
src/ the library — core/ (framework-free logic), components/, composables/
test/ Vitest suites; the executable specification
demo/ full sample application (maps, Monaco, Markdown, 16 panels)
playground/ minimal harness used by the browser gates
docs/ manual, ADRs, parity and plan
scripts/gates/ the verification gates
docs/evidence/ a written record per milestone gate (the gate's own output is not committed)Development
npm install
npm test # Vitest
npm run typecheck # vue-tsc
npm run lint # ESLint
npm run build # library build + .d.ts + styles.css
npm run demo # the demo app
npm run playground # the minimal harness
npm run gate -- M14 # the full standing gate for a milestone
npm run gate:selftest # prove every gate rule is non-vacuous
npm run gate:sweep # coverage + non-vacuity sweepnpm run gate -- M<n> runs types, lint, tests, build, test counts, the CSS-prefix and
API-surface checks, the docs/API cross-check, the demo build, the milestone's own rules,
and a real-Chrome browser gate. Gates are never edited to make a run pass.
Continuous integration
Two workflows, both on Node 22 (vitest 5 will not run on Node 20):
.github/workflows/gate.ymlrunsnpm run gate -- M14on every push and pull request, browser gate included — the runner image already ships Chrome — and keeps the gate's evidence as a build artifact..github/workflows/pages.ymlbuilds the demo and publishes it to GitHub Pages on each push tomain: the landing page at the site root, the demo under/demo/. The demo'sbaseis relative, so no deployment path is baked into the build.
License
MIT
