Workspaces
Workspaces are complex window arrangements hosted within a single frame. They allow you to organize multiple applications into rows, columns, and tab groups — creating a unified multi-app experience.
Workspace Hierarchy
Every workspace follows this containment hierarchy:
- Frame — the outermost window (Workspaces App) that hosts one or more Workspaces
- Workspace — a single layout configuration within a Frame
- Box Elements — structural containers:
Row,Column,Group(tabs) - WorkspaceWindow — individual app windows placed inside Box Elements
Visual hierarchy
Frame
├── Workspace "Trading View"
│ ├── Row
│ │ ├── Window (ClientList)
│ │ └── Column
│ │ ├── Window (Portfolio)
│ │ └── Window (OrderTicket)
│ └── Group (tabs)
│ ├── Window (Chart)
│ └── Window (News)
└── Workspace "Research View"
└── ...Required Setup
The Workspaces API requires the @interopio/workspaces-api library, which is passed as a plugin during initialization:
Initialize with Workspaces API
import IODesktop from "@interopio/desktop";
import IOWorkspaces from "@interopio/workspaces-api";
import { IOConnectProvider } from "@interopio/react-hooks";
import type { IOConnectInitSettings } from "@interopio/react-hooks";
const settings: IOConnectInitSettings = {
desktop: {
factory: IODesktop,
config: {
libraries: [IOWorkspaces], // Enable Workspaces API
},
},
};Creating a Workspace
io.workspaces.createWorkspace(definition: WorkspaceDefinition, config?: WorkspaceConfig): Promise<Workspace>
Create a workspace from definition
const workspace = await io.workspaces.createWorkspace({
children: [
{
type: "row",
children: [
{ type: "window", appName: "ClientList" },
{
type: "column",
children: [
{ type: "window", appName: "ClientPortfolio" },
{ type: "window", appName: "OrderTicket" },
],
},
],
},
],
config: {
title: "Wealth Management",
},
});
console.log("Workspace ID:", workspace.id);Using the Builder API
For more complex layouts, the Builder API provides a fluent interface:
Builder API
const builder = io.workspaces.getBuilder({
type: "workspace",
definition: { config: { title: "Trading View" } },
});
builder
.addRow()
.addWindow({ appName: "MarketData" })
.addWindow({ appName: "Chart" });
builder
.addGroup()
.addWindow({ appName: "OrderTicket" })
.addWindow({ appName: "TradeHistory" });
const workspace = await builder.create();Restoring a Workspace
Saved workspace layouts can be restored by name:
Restore a saved layout
const workspace = await io.workspaces.restoreWorkspace("Trading View", {
context: { selectedClient: "C-101" },
});Workspace Context
Each workspace has its own isolated context for multi-tasking scenarios. This is different from global Shared Contexts — workspace context is scoped to that specific workspace instance.
Workspace-scoped context
// Set workspace context
await workspace.setContext({
selectedClient: "C-101",
view: "portfolio",
});
// Get workspace context
const ctx = await workspace.getContext();
// Subscribe to workspace context changes
workspace.onContextUpdated((context) => {
console.log("Workspace context changed:", context);
});Workspace Context ≠ ChannelsWorkspace Context is local to a workspace instance. Channels are global. Apps in a workspace can still use global Channels, but the channel itself is not "workspace-specific."
Locking Controls
Workspaces support granular locking to control what users can modify:
Lock workspace elements
await workspace.lock({
allowExtract: false, // Prevent dragging windows out
allowSplitters: false, // Lock splitter positions
allowDrop: false, // Prevent dropping windows in
showCloseButton: false, // Hide close buttons
showAddWindowButtons: false,
});Workspace Events
Listen to workspace events
// Window added to workspace
workspace.onWindowAdded((window) => {
console.log("Window added:", window.appName);
});
// Window removed from workspace
workspace.onWindowRemoved((removed) => {
console.log("Window removed:", removed.windowId);
});
// Workspace closed
workspace.onClosed(() => {
console.log("Workspace closed");
});