Overlays & full-screen
Dialog, Sheet, Drawer and full-screen views are the four surfaces a user can be shifted onto. They look similar but each has one clear job. This is how we pick between them at Yuno.
The surface ladder
This is the decision, and it runs BEFORE you pick components. Walk it down and stop at the first yes. Every question is about something you can count in the file, which is deliberate: the old first question was "do you need the list behind as context?", and nobody has ever answered no to that.
- 1Step 0 — Does it need an address? Is it shared by link, reached from more than one place, or does the browser back button have to work on it?
Use: Full-screen. It is a route, not an overlay, so nothing below this matters. Rule details, payment details, dispute details.
- 2Step 1a — Does it hold a collection you browse? A Table, a search or filter control, or more than five selectable rows.
Use: Sheet, right side. Any single yes in step 1 is enough; you do not need all three.
- 3Step 1b — Does it scroll on its own? An overflow-auto or a max-h on the body.
Use: Sheet. A body that needs a scroll is a body that did not fit, and a Sheet is full height for free.
- 4Step 1c — Does it ask for more than three fields? Count every Input, Select, Textarea, Combobox, RadioGroup and date picker.
Use: Sheet. Three is the line: four is a form, and a form in a centred modal is cramped.
- 5Step 2 — All three said no.
Use: Dialog. A short blocking question or one to three fields. This is the DEFAULT, not the fallback: most overlays land here.
- 6The one exception — does it open from inside a Sheet?
Use: Dialog, and only here may it grow past the canonical width. Sheet-on-Sheet is forbidden and full-screen would throw away the parent Sheet's state, so Dialog is the only surface left. If you can reach the same surface from a page, this exception does not apply to you.
- 7Only for mobile prototypes — is a bottom sheet with drag-to-dismiss the native gesture here?
Use: Drawer. The Dashboard is desktop-first, so this is rare. On desktop there is no gesture and the expectation is a side panel: use a Sheet.
Quick pick
One line to decide, if you're in a hurry. The rest of the page is the reasoning.
A short, blocking decision. Confirm, cancel, quick form of 1 to 3 fields. Modal, centered, small.
A side or bottom panel to create, edit or view details while the list behind stays as context. Desktop canonical for both short-to-medium create flows (payment link, rule, blocklist) and row-detail editing.
A mobile-first bottom sheet with drag-to-dismiss and snap points. In the Yuno Dashboard (desktop-first) it's rare, use it only in mobile surfaces.
A page of its own with URL, breadcrumbs and its own layout. Rule details, payment details, dispute details. Use when the object is complex enough to earn its own screen.
How they compare
The characteristics that push you toward one and away from another.
| Characteristic | Dialog | Sheet | Drawer | Full-screen |
|---|---|---|---|---|
| Purpose | Confirm, decide, quick 1-3 field form. | Create, edit or view details while keeping list context. | Mobile bottom sheet with gesture affordance. | Explore or edit a complex object as its own page. |
| Blocks the app | Yes, modal. | Yes, with a dimmer. | Yes, with a dimmer + scale. | No, it's a route. |
| Anchor | Centered. | Right (canonical) / left / top / bottom. | Bottom by default. | N/A, full viewport. |
| Size | Small, content-driven. | Up to 768px wide (right/left) or full width (top/bottom). | Bottom, supports snap points. | 100% of the main region. |
| Dismiss | ESC, overlay click, Cancel. | ESC, overlay click, X button. | Drag down, ESC, overlay click. | Back / breadcrumb / route change. |
| Has its own URL | No. | No. | No. | Yes, and it's shareable. |
| Preserves list context | Yes, list stays visible behind the modal. | Yes, list stays visible next to the panel. | Partially, list is dimmed underneath. | No, list is replaced by the detail page. |
| Yuno usage | Confirmations, quick actions. | Long create forms (payment link, rule, blocklist), row-level details, edit-in-place, filters. | Rare on Dashboard (mobile surfaces only). | Rule details, payment details, dispute details. |
About full-screen
Full-screen isn't a component in the kit. It's a routing decision.
Multi-step within a single component
All four surfaces (Sheet, Drawer, Dialog, full-screen view) support internal multi-step flows. The header can host a back arrow (ArrowLeft) so the user moves between steps without leaving the component. Same instance, different body content.
The back arrow lives in the SheetHeader (left of the SheetTitle). Body content changes as the user progresses. Use when each step is a medium form (multiple inputs, some data, a section or two). Typical for create flows like rule → condition → operand, or payment link → recipient → amount.
The back arrow lives in the DrawerHeader. Body content swaps between steps just like Sheet. Uncommon in the Yuno Dashboard (desktop-first), but valid when a mobile prototype needs a multi-step bottom sheet with drag-to-dismiss between steps.
The Dialog header can carry a back arrow for a short multi-step flow. Use when each step is small (2-3 inputs or a simple choice), like 'choose action → confirm details'. If any single step needs a longer form, jump to Sheet.
A wizard route or step-by-step page. The back arrow lives in the PageHeader or is replaced by a Stepper. Use when steps carry long forms, lots of content, or dense info that would feel cramped inside a Sheet.
See it in action
Two real multi-step flows. The Sheet on the left carries a heavy form across 3 steps, the Dialog on the right handles a short 2-step decision. Same navigation pattern (back arrow in header, step indicator in footer), different amount of content per step.
How to pick the container for a multi-step flow
The number of steps doesn't decide — the volume of content PER STEP does. Same 3-step flow can live in a Dialog, a Sheet or a full-screen view depending on how heavy each step is.
| Content per step | Use | Example |
|---|---|---|
| Small — 2 to 3 inputs, a single choice, or a short confirmation. | Dialog | Choose action → confirm details. Small enough that the modal doesn't feel cramped. |
| Medium — a form with multiple inputs, a section or two, some data to review. | Sheet | Payment link create → recipient step (email, name, phone) → amount step (currency, value, description). |
| Large — long forms, many inputs, dense info, complex configuration. | Full-screen view | Rule create wizard — conditions with nested logic, actions across multiple providers, priority + scheduling. |
Canonical Yuno mapping
Real Dashboard scenarios and which surface they use today. Use as a starting point when your case matches.
| Scenario | Surface | Why |
|---|---|---|
| Delete a rule, list, route or connection | Dialog | Blocking decision with a single copy line and 2 buttons. Uses Primary (not destructive red) inside a Dialog — clarity comes from copy. |
| Quick create (name + 1-2 fields) | Dialog | Small form, no lateral context needed. The user's attention should collapse to the form. |
| Create a long-form object (payment link, rule, blocklist) | Sheet | Multi-field forms that don't earn their own page. Right-anchored Sheet gives room for stacked fields and validation without losing the list where the new item will land. |
| Edit a row without leaving the table | Sheet | Keeps the table visible as context. Right-anchored is canonical, up to 768px wide. |
| Filter a list | Sheet | Left-anchored filter panel. The list stays visible so the user sees the filter effect land. |
| Rule details (conditions + actions + logs) | Full-screen | Complex object with tabs, its own scroll, and worth sharing by URL. A Sheet would feel cramped. |
| Payment details (timeline, events, metadata) | Full-screen | Long, scrollable, cross-linked from other places (alerts, disputes). Needs its own URL. |
| Dispute details (case builder + evidence uploads) | Full-screen | Multi-step, uploads, its own workflow. It's a page, not a panel. |
| Mobile-only checkout preview inside a prototype | Drawer | Bottom-anchored with drag-to-dismiss feels native in mobile surfaces. Rare in the Dashboard itself. |
| Manage secondary items (templates, presets, saved views, member picker) opened from inside a Sheet flow | Dialog (wide) | Sheet-on-Sheet is forbidden and Full-screen would drop the user out of the parent Sheet. Dialog is the only surface that respects both. In this case Dialog can grow up to sm:max-w-4xl and carry non-form content (tables, lists with actions, pickers, tabs). See the exception section below. |
AlertDialog: Dialog with stricter dismissal
AlertDialog is not a 5th surface — it's a specialization of Dialog. Same visual anatomy (Header + Body + Footer with borders), same size (~448px, mobile with 16px gutters), same 'Body is required' + 'title-only 99%' + 'never destructive red' rules. The only difference is stricter dismissal semantics + role='alertdialog' for screen readers.
| Characteristic | Dialog | AlertDialog |
|---|---|---|
| Dismiss with ESC | Yes. | No — user MUST click Cancel or Action. |
| Dismiss by clicking overlay | Yes. | No — user MUST click Cancel or Action. |
| Close X in corner | Yes, absolute top-6 right-6. | No — intentionally omitted. |
| Screen reader role | role='dialog'. | role='alertdialog' — announced with more urgency. |
| Use for | Confirmations, quick create, multi-step, all routine decisions (99% of cases). | Irreversible actions where accidental dismiss would be harmful (delete workspace, sign out with unsaved changes, discard changes). |
| Anatomy | Header + Body + Footer with borders (canonical). | Same as Dialog — Header + Body + Footer with borders. |
Exception: management surfaces opened from inside a Sheet
One combination lets Dialog carry more than a small form and grow beyond the default width. It kicks in when the parent surface is already a Sheet AND the user needs a secondary surface to manage saved items (templates, presets, filter views, member lists, etc.). Under that specific setup, Dialog is the only surface left that respects both the stacking rule and the parent flow.
- Sheet-on-Sheet is forbidden by the stacking rule. See the antipatterns below.
- Full-screen would drop the user out of the parent Sheet, forcing them to reopen and reconfigure everything they had in progress (the export they were composing, the filter they were editing).
- Dialog-on-Sheet is the only allowed 2-layer stack. It preserves the parent Sheet exactly where the user left it.
- Content beyond forms: tables, lists with row actions, pickers, previews, tabs, empty states.
- Width beyond default: up to sm:max-w-4xl (~896px), instead of the standard sm:max-w-md (~448px).
- Scrollable body: max-h-[60vh] overflow-auto on the DialogBody when the content is longer than the viewport.
- If the same management surface can be opened from a regular page (not from a Sheet), use the correct surface per the canonical mapping: Full-screen if it deserves a URL, Sheet if it wants to preserve list context on that page.
- If the surface has its own URL, is deep-linked, or is entered from multiple places, redesign the flow so it opens from a page instead of from a Sheet. Then it becomes Full-screen and this exception is not needed.
- The Dialog is still transient. When the user closes it, they return to the parent Sheet exactly where they were. If your surface needs to persist independently of the Sheet, it should be Full-screen.
- Manage saved templates opened from inside the Export drawer (Payments and Reconciliations).
- Column preset picker opened from inside a Sheet that configures a table view.
- Saved filter view manager opened from inside a filter Sheet.
- Workspace member picker opened from inside a share / permissions Sheet.
- Using a Dialog for something with more than 3 fields. It ends up cramped, use a Sheet or a full-screen page.
- Using a Sheet for a confirmation. Feels heavy for a yes/no decision, use a Dialog.
- Using a Drawer on a desktop-only prototype. There's no gesture and the user expectation is a side panel — use a Sheet.
- Stacking 3 overlays. Never. Maximum is 2 layers, and only in this exact shape: a Dialog on top of a Sheet. Never Sheet on Sheet, never Dialog on Dialog, never Sheet on top of a Dialog — redesign the flow.
- Turning a Sheet into a de-facto page. If it has tabs, a scroll, and its own header, it wants to be full-screen.
Related
The three overlay components, and the base template used for full-screen views.
- DialogSmall blocking modal for confirmations and quick decisions.
- SheetSide/bottom panel that preserves list context.
- DrawerBottom sheet with drag-to-dismiss, mobile-first.
- Base templateShell used for full-screen routes (Sidebar + TopBar + main).