FocusLayout
<FocusLayout> is the wizard / onboarding shell — close button + breadcrumb top-left, optional stepper below, body in the middle, sticky action bar at the bottom. No sidebar, no app chrome — distraction-free.
When to use
- “Create agent” wizards.
- Onboarding flows that the user starts and finishes in one session.
- Any flow where the app sidebar would distract from the task.
Don’t use FocusLayout for: detail pages with tabs (DetailPageBar is correct), settings sub-pages, or modals (use Dialog).
Default
- Basics
- Tools
- Review
Step 1 body…
<FocusLayout breadcrumb={['Agents', 'Create']} stepper={{ current: step, steps: ['Basics', 'Tools', 'Review'] }} onClose={() => router.push('/agents')} actions={ <> <Button variant="outline" disabled={step === 1} onClick={back}>Back</Button> <Button onClick={next}>{isLast ? 'Submit' : 'Next'}</Button> </> }> {/* step body */}</FocusLayout>API
| Prop | Type | Default | Description |
|---|---|---|---|
closeTo | string | — | URL the ✕ button navigates to. Ignored when onClose / closeAction is set. |
onClose | () => void | — | Preferred for SPA routers. Called by ✕ and Esc. |
closeAction | ReactNode | — | Replace the default ✕ with a custom node — typically a ConfirmPopover for confirm-on-discard. |
breadcrumb | ReactNode[] | — | Optional breadcrumb shown next to the ✕. |
stepper | { current, steps, orientation? } | — | Stepper config. Renders below the close + breadcrumb row. |
actions | ReactNode | — | Sticky bottom action-bar content. Right-aligned cluster. |
closeLabel | string | "Close" | Close-button aria-label. |
ariaLabel | string | — | Accessible title — defaults to last breadcrumb entry. |
children * | ReactNode | — | Body content for the active step. |
Design guidelines
✓ Do
- Use closeAction with a ConfirmPopover when the flow has unsaved state ("Discard changes?").
- Cap steps at 5. Past that, the user can't hold the path in their head.
- Place primary action on the right of the action bar; Back / Cancel on the left.
✗ Don't
- Add a sidebar inside FocusLayout. The whole point is to hide app chrome.
- Allow forward jumps to unvisited steps. The Stepper inside FocusLayout is intentionally linear.
- Use FocusLayout for short single-step forms. PageHeader + PageContent is enough.
Accessibility
- Esc triggers
onClose(or followscloseTo). - Focus ring on the close button; first focusable item in the body receives initial focus.
- Stepper exposes
aria-current="step"on the active step.
Related
Stepper— Free-standing stepper for in-page wizards.Dialog— Modal flavor for shorter “create” flows.ConfirmPopover— For closeAction confirm-on-discard.