Skip to main content

Options

Window owns the same slots as AppShellheader and chat (shown in both states), plus rail and artifact (fullscreen only) — and presents them in one of two sizes.

Window States

Docked (shown above) is a fixed-size floating panel — header + chat, anchored bottom-right by default — that sits non-modally over the rest of the page. Fullscreen (shown here) is a modal takeover revealing the full AppShell: header, rail, chat, and artifact, over a scrim, with focus trapped inside. The header and chat nodes are the same React instance in both states — same DOM, scroll position, and in-flight state — so expanding or restoring never resets the conversation.

Open Control

Open/close and docked/fullscreen work uncontrolled by default (seeded by defaultOpen / defaultState), or controlled by passing open / state alongside onOpenChange / onStateChange so an external store can be the source of truth. Either way, drive the same transitions imperatively via the AppSurfaceHandle — from a parent through controlRef (as shown here, with an external launcher button), or from inside the window (a header button, or a card in the chat) via useAppSurface().

Behavior

Both states share one surface, so the panel animates between them, and the docked panel can be repositioned.

Maximize and Restore

The header’s maximize control expands the docked panel into the fullscreen modal shell; restore (or Esc) shrinks it back. Docked and fullscreen share one surface, so the panel visibly grows and shrinks between the two rects rather than swapping instantly.

Drag

Docked, the panel is draggable: spread the surface’s dragHandleProps (from controlRef / useAppSurface()) onto a leading header action — here an IconGrip — to turn it into a grip that moves the panel anywhere in the viewport. Arrow keys nudge it too, for keyboard users. The dragged position survives a maximize→restore round-trip (restore returns to it) and resets to the default corner only on close.

Scrim Dismiss

Fullscreen is modal: a scrim sits behind the shell and dismisses back to docked on click, the same as pressing Esc. Because the shell fills the viewport, the scrim itself has no visible edge — the affordance is the dismissal, not a visible backdrop.

Keyboard Interaction

Users can maximize, restore, move, and dismiss a window using standard keyboard controls.

Patterns that use this component

Last modified on July 24, 2026