Dialogs

Dialog

Edge sheet for focused tasks that interrupt the page — confirmations, forms, and nested drill-downs.

Base UI


Dialog opens a bottom edge sheet for tasks that need attention without leaving the page. Compose Dialog.Trigger (usually a Button or IconButton via render), a titled Dialog.Sheet, and Dialog.Close for actions that should dismiss. Portal, backdrop, handle, and heading chrome live inside the sheet — they are not separate public parts.

Pass title for assistive technologies, and add description when the heading alone is thin. Snap points and swipe dismissal live on the Dialog root when the sheet should drag between heights. Nest another Dialog inside Dialog.Sheet for drill-down settings; Escape closes only the topmost layer. Wrap the app once in Dialog.Provider, Dialog.IndentBackground, and Dialog.Indent when the shell should scale down behind an open sheet.


Anatomy

Import the component and assemble its parts:

import { Dialog } from '@viraui/react';

<Dialog.Provider>
  <Dialog.IndentBackground>
    <Dialog.Indent>
      <Dialog>
        <Dialog.Trigger />
        <Dialog.Sheet>
          <Dialog.Close />
        </Dialog.Sheet>
      </Dialog>
    </Dialog.Indent>
  </Dialog.IndentBackground>
</Dialog.Provider>

When to use

  • Confirmations, short forms, and settings that interrupt the page without navigating away
  • Nested drill-down flows where each layer keeps its own title and close
  • Multi-height sheets that preview content, then expand (snap points)

When not to use

  • Small anchored hints or command rows → Popover or Menu
  • Non-blocking save, undo, or status feedback → Toast
  • Long reading that belongs on its own route rather than a sheet

  • Toast — brief, non-blocking feedback after an action
  • Popover — anchored panels that do not block the page
  • Menu — command lists anchored to a trigger

Common examples

Confirmation

A confirmation sheet with trigger, titled sheet, and footer actions is the default interruption pattern. Wrap dismiss and commit buttons in Dialog.Close so both paths close the sheet.

Prefer an explicit footer action as the primary close path rather than relying only on backdrop press or swipe.

Close button

Turn on showCloseButton when the sheet needs the chrome dismiss control in the header (read-only notices, catch-up panels). Footer Dialog.Close actions remain optional when that glyph is enough.

The drag handle stays on by default; set showHandle={false} when the sheet should not invite swipe resize.

Nested sheets

Nest another Dialog inside Dialog.Sheet children for drill-down flows. Each layer keeps its own trigger, title, and close controls. Escape and the topmost close dismiss only the front sheet; the parent stays open underneath.

Snap points

Pass snapPoints (and controlled snapPoint / onSnapPointChange, or defaultSnapPoint) on the Dialog root when the sheet should settle at more than one height. Two points cover preview → full: the preview snap shows a short excerpt plus Read more; that control moves the sheet to full and then disappears so it only exists on the intermediate step.

Background indent

Wrap the app once in Dialog.Provider, Dialog.IndentBackground, and Dialog.Indent when the shell behind an open sheet should scale down (zoom-out). Put page chrome inside Dialog.Indent; keep IndentBackground as a sibling. Sheets still compose as usual under that shell.

Indent is optional bootstrap for the scale effect. Without it, sheets still open — the page behind them just stays full size.

Ask your agent

Add a delete confirmation flow on this settings screen. The danger zone opens a bottom sheet with title, short description, Cancel, and Confirm delete. Screen readers need the same context as sighted users.

Last updated on

On this page