Docs / SDK / Workspace Shell

Workspace Shell

The workspace shell gives your application a professional multi-module layout with menu bars, toolbars, dock zones, and a central canvas area -- the same patterns used by Linear, Figma, and Raycast.

Architecture

The workspace shell is composed of four layers that nest in a specific order. The headless substrate layer defines the configuration as pure data, and the React UI layer renders it:

import { SubstrateRenderer } from "@substrateui/ui/core";
import { ModuleProvider } from "@substrateui/ui/workspace";
import { WorkspaceProvider } from "@substrateui/ui/workspace";
import { WorkspaceShell } from "@substrateui/ui/workspace";
import { createModuleRegistry } from "@substrateui/substrate/modules";
import { financeModule, crmModule } from "@substrateui/templates";

const registry = createModuleRegistry(financeModule, crmModule);

export default function App() {
  return (
    <SubstrateRenderer density="compact" theme="dark">
      <ModuleProvider registry={registry}>
        <WorkspaceProvider defaultModuleId="finance">
          <WorkspaceShell showSwitcher canvasRenderers={canvasRenderers} />
        </WorkspaceProvider>
      </ModuleProvider>
    </SubstrateRenderer>
  );
}

Provider nesting

Each provider has a specific responsibility:

SubstrateRenderer

Root wrapper. Provides ThemeProvider (light/dark/system) and DensityProvider (compact/comfortable/spacious) to all children.

ModuleProvider

Takes a ModuleRegistry and resolves all entity types, commands, hotkeys, and signals into flat registries. Access via useModules().

WorkspaceProvider

Manages workspace state: active module, panel visibility, panel sizes, collapsed zones, canvas type. Access via useWorkspaceStore().

WorkspaceShell

The visible shell. Reads the active module's WorkspaceShellConfig and renders the menu bar, toolbar, dock zones, canvas, and status bar.

WorkspaceShellConfig

Every module defines its workspace layout as a WorkspaceShellConfig object. This is pure data -- no React, no side effects:

import {
  workspaceShell,
  menuBar,
  toolBar,
  statusBar,
  dockZone,
  canvasSlot,
  standardFileMenu,
  standardEditMenu,
  standardViewMenu,
  standardStatusBar,
} from "@substrateui/substrate/workspace";

const workspace = workspaceShell({
  menuBar: menuBar([
    standardFileMenu(),
    standardEditMenu(),
    standardViewMenu(),
    wsMenuItem("tools", "&Tools"),
  ]),

  toolBar: toolBar([
    toolBarGroup("primary", [
      toolBarButton("new", { label: "New", icon: "plus", commandId: "entity.create" }),
      toolBarButton("import", { label: "Import", icon: "upload" }),
      toolBarSeparator(),
      toolBarToggle("filter", { label: "Filter", icon: "filter", active: false }),
    ]),
  ]),

  canvas: canvasSlot("data-grid", {
    availableCanvases: [
      canvasView("data-grid", "Table", { icon: "table" }),
      canvasView("kanban", "Board", { icon: "columns" }),
      canvasView("dashboard-grid", "Dashboard", { icon: "layout-dashboard" }),
    ],
    showViewSwitcher: true,
  }),

  dockZones: [
    dockZone("left", [
      { id: "explorer", label: "Explorer", icon: "folder-tree" },
      { id: "search", label: "Search", icon: "search" },
    ], { defaultSize: 240, collapsible: true }),

    dockZone("right", [
      { id: "inspector", label: "Inspector", icon: "panel-right" },
    ], { defaultSize: 320, collapsed: true }),
  ],

  statusBar: standardStatusBar([
    statusBarItem("record-count", "text", { label: "0 records" }),
  ]),
});

Menu bar

The menu bar supports keyboard navigation with access keys (use & prefix in labels), submenus, separators, checkboxes, radio groups, and conditional visibility. Standard menus (File, Edit, View) are provided as helpers that you can extend with module-specific items:

import { standardFileMenu, wsMenuItem, wsMenuSeparator, submenu } from "@substrateui/substrate/workspace";

// Extend the standard File menu with module-specific items
const fileMenu = standardFileMenu([
  wsMenuSeparator(),
  wsMenuItem("export-csv", "Export as CSV", { shortcut: "Cmd+Shift+E" }),
  submenu("export-more", "Export as...", [
    wsMenuItem("export-json", "JSON"),
    wsMenuItem("export-pdf", "PDF"),
  ]),
]);

Toolbar

Toolbars are organized into groups that can be aligned left, center, or right. Each item can be a button, toggle, dropdown, split button, or separator. Items support badges, accent colors, and conditional visibility via showWhen:

toolBar([
  toolBarGroup("actions", [
    toolBarButton("new", { label: "New", icon: "plus", commandId: "entity.create" }),
    toolBarButton("delete", { label: "Delete", icon: "trash", variant: "destructive" }),
  ], { align: "left" }),

  toolBarGroup("views", [
    toolBarToggle("grid", { label: "Grid", icon: "grid", active: true }),
    toolBarToggle("list", { label: "List", icon: "list" }),
  ], { align: "right" }),
], { position: "top", density: "compact" })

Dock zones

Dock zones define resizable, collapsible panel areas on the left, right, and bottom of the canvas. Each zone contains panels that render as tabs:

dockZone("left", [
  { id: "explorer", label: "Explorer", icon: "folder-tree" },
  { id: "bookmarks", label: "Bookmarks", icon: "bookmark" },
], {
  defaultSize: 240,
  minSize: 180,
  maxSize: 400,
  collapsible: true,
  collapsed: false,
  resizable: true,
})

Canvas renderers

The canvas is the central content area. You register React components for each canvas type and the shell renders the active one:

const canvasRenderers: Record<string, React.ComponentType<{ moduleId: string }>> = {
  "data-grid": DataGridCanvas,
  "kanban": KanbanCanvas,
  "dashboard-grid": DashboardCanvas,
  "accounting-sheet": AccountingCanvas,
};

<WorkspaceShell canvasRenderers={canvasRenderers} />

Built-in canvas types include data-grid, kanban, accounting-sheet, timeline, calendar, dashboard-grid, node-editor, infinite-canvas, and custom.

Live demo

See the workspace shell in action with all 7 template modules loaded: