Panes
This is a guide, not the contract. What the platform guarantees is specified under
openspec/specs/. For this page:panes·host-services. Where this page and a specification disagree, the specification is right, and that is a defect in this page: change the behaviour there, then explain it here.
The arrangement side of the content area: the panes your tabs sit in.
Do it
const panes = inject(PaneService);
panes.splitRight(); // duplicate what the address pane shows, like the toolbar buttonpanes.splitDown(handle);panes.closePane(handle); // asks about unsaved work exactly as the × wouldpanes.unsplit(); // back to one pane; asks if a sibling holds unsaved workpanes.maximize(handle); panes.minimize(handle); panes.restore(handle);panes.focus(handle); // move the address to that panepanes.moveTab('doc/readme', handle);Read it
panes.panes(); // PaneFacts[] in layout order: handle, showing, itemCount, …panes.activePane(); // the handle of the pane carrying the addresspanes.isSplit(); // Signal<boolean>panes.maximized(); // PaneHandle | nullpanes.minimized(); // readonly PaneHandle[]panes.exists(handle); // whether the handle still names a paneEvery pane of the content area is listed by panes(), in layout order, as PaneFacts: handle, showing (the path shown, or null), itemCount, carriesAddress, maximized, minimized. The handle of the pane carrying the address is activePane(). The area as a whole is answered by isSplit(), maximized() and minimized(). Nesting and proportions are not published: bind your own controls to these signals and they follow the user.
@if (panes.isSplit()) { <button (click)="panes.unsplit()">Single pane</button> }What asks about unsaved work
closePane asks about the unsaved work of the pane it closes, exactly as the pane’s × would. unsplit asks for every sibling pane it drops. Splitting never asks: it does nothing when what the pane shows cannot be shown in a second pane.
Switched off
content.splitRight, content.splitDown, content.maximize, content.minimize and content.close take the toolbar buttons, the drop edges and mod+\ away from the user. Every action here keeps working for you, which is how you offer it from your own control.
In depth
Two services, one boundary. Content is ContentTabsService: which items are open, which is
active, opening, navigating, pinning, closing an item. Arrangement is PaneService: the panes those
items sit in, splitting, closing a pane, filling the area, collapsing, where the address lives.
Neither knows the other’s job.
Handles. An action takes a PaneHandle, which the facts hand you. A handle is opaque and
stable for as long as its pane exists: it survives focus changes, splits elsewhere and restarts, so
you may keep it. Once the pane is gone the handle names nothing, and every action given it does
nothing rather than acting on another pane. Without a handle an action means the pane that carries
the address, which is what a toolbar on that pane means too.
Same code as the controls. Each action is the one the pane toolbar, the tab menu and the
shell.content.splitRight chord run, with the guards listed under What asks about unsaved work.
The switches do not reach the service, as Switched off says.
What the controls do. Every content pane shows the same inline toolbar: New tab, Split right, Split down, Minimize, Maximize and Close. The toolbar split duplicates the active tab into a new pane and the tab stays where it is; dragging a tab, or its Split right/down menu entry, moves it. The split buttons appear only when the active content can be shown in a second pane. Maximize fills the whole viewport over all chrome; Escape or the button restores it. Minimize collapses a pane in a split to a thin strip showing the active tab’s icon and name, with the tab count when the pane holds several; clicking the strip restores the pane. Minimize and Close appear on both panes of a split, and closing the address pane dissolves the split, the neighbour taking over the address. With a single pane only Maximize is shown. A pane that holds no tabs has no strip and gets a floating toolbar instead, and a chromeless screen shows no strip at all, however many tabs are parked behind it. Both regain the strip as soon as they hold a tab and the chromeless screen is left, because a tab the strip does not draw would be a tab nobody can reach again.
Scope. PaneService addresses the content area. Panes inside sidebars are not reachable through
it.
Where the story is told
- Tabs: the content side of the same area.
- Switching capabilities off: what the toolbar offers and how to take it away.