Component
Vue Desktop Layout Component
DomDesktopLayoutA minimal application rail with hover shortcuts, independent navigation, and a flexible workspace.
A controlled application shell
The host supplies ordered pinned apps and owns active selection, shortcuts, and content. Hover or focus an app to see its submenu.
Inbox
App-owned navigation
Inbox
All messages
npm install @getdom/studio<script setup>
import '@getdom/studio/style.css';
import { ref } from 'vue';
import { DomDesktopLayout } from '@getdom/studio';
const active = ref('inbox');
const apps = [
{ id: 'inbox', label: 'Inbox', icon: 'M4 5h16v14H4zM4 13h5l2 3h2l2-3h5', items: [{ id: 'unread', label: 'Unread messages' }] },
{ id: 'files', label: 'Files', icon: 'M3 6h7l2 2h9v12H3z' },
];
const view = ref('All messages');
const sidebarSize = ref(256);
/**
* Apply a shortcut using application-owned view state.
* @param {{ item: { label: string } }} selection Selected shortcut.
* @returns {void}
*/
function navigate({ item }) {
view.value = item.label;
}
</script>
<template>
<DomDesktopLayout v-model="active" v-model:sidebar-size="sidebarSize" :apps="apps" height="30rem" @shortcut="navigate">
<template #sidebar="{ app }"><div class="p-5"><h2 class="text-sm font-medium">{{ app?.label }}</h2><p class="mt-4 text-xs text-muted-fg">App-owned navigation</p></div></template>
<template #default="{ app }"><div class="p-8"><h1 class="text-xl font-medium">{{ app?.label }}</h1><p class="mt-3 text-sm text-muted-fg">{{ active === 'inbox' ? view : 'Your files' }}</p></div></template>
</DomDesktopLayout>
</template>
Compose a workspace
Use unique string app IDs and shortcut IDs. Icon values are SVG path data. The active ID should belong to the supplied pinned apps; otherwise scoped slots receive a null app. Empty rails still expose the manage-apps action.
The sidebar uses DomSplitterPanel with transparent handles. Drag its subtle divider or use arrow keys (Shift for larger steps) to resize it. Bind v-model:sidebar-size to save the width; minSidebarSize and minWorkspaceSize keep both areas usable. The sidebar can sit left or right, or be hidden for a full-stage app. On compact screens it becomes a toggleable overlay. Its slot receives a close helper for navigation actions. The default slot owns its scrollable stage; give child panes explicit heights when they own scrolling.
Apps, installation, saved pin order, permissions, routing, and state retention belong to the host. The shell emits selection intents and never loads plugins or makes network requests.
Try the complete desktop workspace and Electron host →Props
Props
Control props
| Name | Type | TS | Default | Description |
|---|---|---|---|---|
modelValue | string | string | '' | — |
apps | array | Array<unknown> | [] | Ordered pinned apps: unique id, label, SVG path icon, optional items with id and label. |
height | string | string | '100dvh' | Use 100% only inside a parent with an explicit height. |
sidebarPosition | 'left' | 'right' | string | 'left' | Which side of the workspace contains app navigation. |
sidebarWidth | string | string | '16rem' | Compact overlay width as a CSS length. |
sidebarSize | number | number | 256 | Desktop sidebar width in pixels. Bind v-model:sidebarSize to save user resizing. |
minSidebarSize | number | number | 180 | — |
minWorkspaceSize | number | number | 280 | — |
showSidebar | boolean | boolean | true | — |
Auto-generated from Desktop layout.props and inline _edit hints.
Slots
| Name | Scope | Description |
|---|---|---|
| #titlebar | — | Optional native host title bar. The host owns window controls and drag regions. |
| #sidebar | { app, close } | App-specific navigation; placed left or right and shown as an overlay on mobile. |
| #(default) | { app } | The active app workspace. The application owns state retention and routing. |
| #rail-footer | — | Account or settings actions at the bottom of the rail. |