Alert Dialog

A modal dialog for critical confirmations and acknowledgements that require an explicit user decision.

This component uses Radix UI

Alert Dialog interrupts the user’s workflow to communicate critical information or confirm an action that cannot be taken lightly. It presents a short, focused message and requires the user to explicitly confirm or cancel before proceeding.

Use Alert Dialog for actions such as deleting data, performing irreversible changes, or acknowledging important warnings where dismissal without a decision would be unsafe. It is the preferred starting point for critical confirmations when the decision can be explained in a short, focused message.

Loading...
import {
  AlertDialog,
  AlertDialogAction,
  AlertDialogCancel,
  AlertDialogContent,
  AlertDialogDescription,
  AlertDialogFooter,
  AlertDialogHeader,
  AlertDialogTitle,
  AlertDialogTrigger,
  Button,
} from 'ui'
 
export function AlertDialogDemo() {
  return (
    <AlertDialog>
      <AlertDialogTrigger asChild>
        <Button type="outline">Show Alert Dialog</Button>
      </AlertDialogTrigger>
      <AlertDialogContent>
        <AlertDialogHeader>
          <AlertDialogTitle>Create new API keys</AlertDialogTitle>
          <AlertDialogDescription>
            This will create a default publishable key and a default secret key both named{' '}
            <code className="text-code-inline">default</code>. These keys are required to connect
            your application to your Supabase project.
          </AlertDialogDescription>
        </AlertDialogHeader>
        <AlertDialogFooter>
          <AlertDialogCancel>Cancel</AlertDialogCancel>
          <AlertDialogAction>Create keys</AlertDialogAction>
        </AlertDialogFooter>
      </AlertDialogContent>
    </AlertDialog>
  )
}

Installation

npx shadcn-ui@latest add alert-dialog

Usage

import {
  AlertDialog,
  AlertDialogAction,
  AlertDialogBody,
  AlertDialogCancel,
  AlertDialogContent,
  AlertDialogDescription,
  AlertDialogFooter,
  AlertDialogHeader,
  AlertDialogTitle,
  AlertDialogTrigger,
} from '@/components/ui/alert-dialog'
<AlertDialog>
  <AlertDialogTrigger>Open</AlertDialogTrigger>
  <AlertDialogContent>
    <AlertDialogHeader>
      <AlertDialogTitle>Are you absolutely sure?</AlertDialogTitle>
      <AlertDialogDescription>
        This action cannot be undone. This will permanently delete your account and remove your data
        from our servers.
      </AlertDialogDescription>
    </AlertDialogHeader>
    <AlertDialogFooter>
      <AlertDialogCancel>Cancel</AlertDialogCancel>
      <AlertDialogAction>Continue</AlertDialogAction>
    </AlertDialogFooter>
  </AlertDialogContent>
</AlertDialog>

Behavior

Unlike a generic Dialog, an Alert Dialog cannot be dismissed by clicking outside the modal. The user must take an explicit action by confirming, cancelling, or pressing Escape.

This enforced decision helps prevent accidental dismissal of critical warnings or destructive actions.

Supabase’s Alert Dialog extends the Radix/Shadcn version with async action handling. When an AlertDialogAction returns a Promise, the dialog keeps focus trapped, blocks dismissal, and shows loading until the Promise resolves. Rejected Promises keep the dialog open so consumers can render inline error feedback.

Guidelines

  • Keep content concise: AlertDialogDescription renders as a single paragraph and must not contain block-level elements such as lists, multiple paragraphs, or complex layouts.
  • Use for critical decisions only: Reserve Alert Dialog for destructive or irreversible actions, or for warnings that require explicit acknowledgement.
  • Use for dirty-form discard confirmation: A short discard-confirmation step after a dirty form dismissal attempt (backdrop, Escape, or Cancel) is a valid Alert Dialog pattern. In Studio, prefer DiscardChangesConfirmationDialog for this flow.
  • Always provide a cancel action: Include AlertDialogCancel so users can safely back out, in addition to supporting the Escape key.
  • Use AlertDialogBody for inline feedback: If async actions can fail, render inline feedback such as an Admonition inside AlertDialogBody so spacing stays consistent.
  • Avoid rich content: If the decision requires detailed explanations, callouts, multiple paragraphs, or form inputs, move to Confirmation Modal or Dialog instead.

See Modality for guidance on choosing the appropriate dialog pattern.

Examples

Async action

When an action returns a Promise, Alert Dialog keeps the dialog open, shows a loading state on the action button, and disables dismissal until the Promise resolves.

Loading...
import {
  AlertDialog,
  AlertDialogAction,
  AlertDialogCancel,
  AlertDialogContent,
  AlertDialogDescription,
  AlertDialogFooter,
  AlertDialogHeader,
  AlertDialogTitle,
  AlertDialogTrigger,
  Button,
} from 'ui'
 
const createApiKeys = async () => {
  await new Promise((resolve) => setTimeout(resolve, 1200))
}
 
export function AlertDialogAsync() {
  return (
    <AlertDialog>
      <AlertDialogTrigger asChild>
        <Button type="outline">Show Alert Dialog</Button>
      </AlertDialogTrigger>
      <AlertDialogContent>
        <AlertDialogHeader>
          <AlertDialogTitle>Create new API keys</AlertDialogTitle>
          <AlertDialogDescription>
            This will create a default publishable key and a default secret key both named{' '}
            <code className="text-code-inline">default</code>. These keys are required to connect
            your application to your Supabase project.
          </AlertDialogDescription>
        </AlertDialogHeader>
        <AlertDialogFooter>
          <AlertDialogCancel>Cancel</AlertDialogCancel>
          <AlertDialogAction onClick={createApiKeys}>Create keys</AlertDialogAction>
        </AlertDialogFooter>
      </AlertDialogContent>
    </AlertDialog>
  )
}

Async action error

Catch errors to show inline feedback, then rethrow so Alert Dialog can reset the loading state and keep the dialog open.

Loading...
import { useState } from 'react'
import {
  AlertDialog,
  AlertDialogAction,
  AlertDialogBody,
  AlertDialogCancel,
  AlertDialogContent,
  AlertDialogDescription,
  AlertDialogFooter,
  AlertDialogHeader,
  AlertDialogTitle,
  AlertDialogTrigger,
  Button,
} from 'ui'
import { Admonition } from 'ui-patterns/admonition'
 
const resetTemplate = async () => {
  await new Promise((resolve) => setTimeout(resolve, 1200))
  throw new Error('Template reset failed')
}
 
export function AlertDialogAsyncError() {
  const [error, setError] = useState<string | null>(null)
 
  const handleResetTemplate = async () => {
    setError(null)
 
    try {
      await resetTemplate()
    } catch (error) {
      setError('Check the template configuration and try again.')
      throw error
    }
  }
 
  return (
    <AlertDialog>
      <AlertDialogTrigger asChild>
        <Button type="outline">Show Alert Dialog</Button>
      </AlertDialogTrigger>
      <AlertDialogContent>
        <AlertDialogHeader>
          <AlertDialogTitle>Reset email template?</AlertDialogTitle>
          <AlertDialogDescription>
            This will replace the current email template with the default version. Any unsaved
            changes will be lost.
          </AlertDialogDescription>
        </AlertDialogHeader>
        {error && (
          <AlertDialogBody>
            <Admonition type="destructive" title="Failed to reset template" description={error} />
          </AlertDialogBody>
        )}
        <AlertDialogFooter>
          <AlertDialogCancel>Cancel</AlertDialogCancel>
          <AlertDialogAction variant="warning" onClick={handleResetTemplate}>
            Reset template
          </AlertDialogAction>
        </AlertDialogFooter>
      </AlertDialogContent>
    </AlertDialog>
  )
}

Close only

Loading...

Warning

Loading...

Destructive

Loading...