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");
});