Skip to content
  • System
  • Light
  • Dark
  • High contrast

Dialog

Two patterns. Use the right one for the context:

  • Action dialog — requires a decision. Footer has Cancel + primary action. No corner ✕.

  • Dismissable dialog — informational or read-only. A Dialog.Close ✕ in the top-right corner is the only close control.

Use when the user must make a decision — e.g. confirming a save or destructive operation. Cancel lives in the footer alongside the primary action.

import { Dialog } from '@eekodigital/raster';

<Dialog.Root>
  <Dialog.Trigger>
    {(props) => <Button {...props}>Edit project</Button>}
  </Dialog.Trigger>
  <Dialog.Portal>
    <Dialog.Overlay />
    <Dialog.Content>
      <Dialog.Title>Edit project</Dialog.Title>
      <Dialog.Description>Make changes to your project settings below.</Dialog.Description>
      {/* form content */}
      <div style={{ display: 'flex', gap: '0.5rem', justifyContent: 'flex-end' }}>
        <Dialog.Close>
          {(props) => <Button variant="secondary" {...props}>Cancel</Button>}
        </Dialog.Close>
        <Button>Save changes</Button>
      </div>
    </Dialog.Content>
  </Dialog.Portal>
</Dialog.Root>

Use for informational content that requires no action. The ✕ button in the top-right corner is the sole close control.

<Dialog.Root>
  <Dialog.Trigger>
    {(props) => <Button variant="secondary" {...props}>View details</Button>}
  </Dialog.Trigger>
  <Dialog.Portal>
    <Dialog.Overlay />
    <Dialog.Content>
      <Dialog.Title>Audit summary</Dialog.Title>
      <Dialog.Description>A read-only summary of the latest audit run.</Dialog.Description>
      <Dialog.Close aria-label="Close">✕</Dialog.Close>
      {/* informational content */}
    </Dialog.Content>
  </Dialog.Portal>
</Dialog.Root>

Always include a Dialog.Close — either in the footer (action dialog) or as the corner ✕ (dismissable dialog). Don’t rely solely on Escape or click-outside; users on touch devices and screen readers need an explicit close target.