> ## Documentation Index
> Fetch the complete documentation index at: https://docs.twenty.com/llms.txt
> Use this file to discover all available pages before exploring further.

# AlertDialog

> Ask for confirmation before an action that needs an explicit decision.

export const StoryEmbed = ({storyId, title, height = 120}) => <>
    <Tabs>
      <Tab title="Light">
        <iframe title={`${title} (light)`} src={`https://storybook.twenty.com/iframe.html?id=${storyId}&viewMode=story&globals=colorScheme:light`} width="100%" height={height} loading="lazy" allow="clipboard-write" style={{
  border: 0
}} />
      </Tab>
      <Tab title="Dark">
        <iframe title={`${title} (dark)`} src={`https://storybook.twenty.com/iframe.html?id=${storyId}&viewMode=story&globals=colorScheme:dark`} width="100%" height={height} loading="lazy" allow="clipboard-write" style={{
  border: 0
}} />
      </Tab>
    </Tabs>
    <a href={`https://storybook.twenty.com/?path=/story/${storyId}`}>
      Open in Storybook
    </a>
  </>;

Use `AlertDialog` for a decision that interrupts the current workflow, such as confirming deletion. It provides `alertdialog` semantics, focus management, and explicit confirmation or cancellation.

This primitive is for standalone Twenty UI and host-owned interfaces. Front components must request a confirmation through the [SDK host dialog API](/developers/extend/apps/layout/front-components#host-communication-api). Direct `Dialog`, `AlertDialog`, and native browser dialogs are prohibited inside the front component renderer.

<StoryEmbed storyId="ui-surfaces-alertdialog--display" title="AlertDialog example" height={440} />

## Usage

### Uncontrolled state

Use `defaultOpen` to set the initial visibility. The dialog owns subsequent changes from its trigger, close controls, and dismissal interactions.

```tsx theme={null}
import { Button } from 'twenty-ui/primitives/input';
import { AlertDialog } from 'twenty-ui/primitives/surfaces';

type DeleteConfirmationProps = { onDelete: () => void };

export const DeleteConfirmation = ({ onDelete }: DeleteConfirmationProps) => (
  <AlertDialog.Root defaultOpen={false}>
    <AlertDialog.Trigger
      render={<Button variant="solid">Delete record</Button>}
    />
    <AlertDialog.Portal>
      <AlertDialog.Backdrop />
      <AlertDialog.Viewport>
        <AlertDialog.Popup>
          <AlertDialog.Header>
            <AlertDialog.Title>Delete this record?</AlertDialog.Title>
            <AlertDialog.Description>
              This record will be permanently deleted. This action cannot be
              undone.
            </AlertDialog.Description>
          </AlertDialog.Header>
          <AlertDialog.Footer>
            <AlertDialog.Close render={<Button>Cancel</Button>} />
            <AlertDialog.Close
              onClick={onDelete}
              render={<Button color="danger">Delete</Button>}
            />
          </AlertDialog.Footer>
        </AlertDialog.Popup>
      </AlertDialog.Viewport>
    </AlertDialog.Portal>
  </AlertDialog.Root>
);
```

`defaultOpen` defaults to `false`, so it can be omitted. This example uses a synchronous confirmation callback and closes after the action runs.

## Anatomy

Keep related parts inside `AlertDialog.Root`, or connect detached triggers through a handle. Compose the portal, backdrop, viewport, and popup separately.

```text theme={null}
AlertDialog.Root
├── AlertDialog.Trigger
└── AlertDialog.Portal
    ├── AlertDialog.Backdrop
    └── AlertDialog.Viewport
        └── AlertDialog.Popup
            ├── AlertDialog.Header
            │   ├── AlertDialog.Title
            │   └── AlertDialog.Description
            ├── AlertDialog.Body
            └── AlertDialog.Footer
                ├── AlertDialog.Close
                └── Confirmation action
```

| Part | Requirement | Purpose |
| - | - | - |
| `Root` | Required | Coordinates open state and modal behavior. |
| `Trigger` | Optional for a programmatically opened dialog | Opens the dialog and provides a return focus target. |
| `Portal` | Recommended | Moves the overlay to its container and controls mounting. |
| `Backdrop` | Optional | Visually separates the alert from the surrounding page. |
| `Viewport` | Recommended | Positions the popup and provides its scrollable surrounding area. |
| `Popup` | Required | Renders the alert content with focus management. |
| `Title` | Recommended | Supplies the visible alert name. An accessible name is always required. |
| `Description` | Recommended for a confirmation | Explains the decision and its consequences. |
| `Header`, `Body`, `Footer` | Optional layout parts | Arrange headings, additional content, and actions. |
| `Close` | Recommended for cancellation | Supplies an explicit close action. |

Set `container` and `keepMounted` on `Portal`, backdrop attributes on `Backdrop`, layout attributes on `Viewport`, and `size` and focus props on `Popup`. Each element part accepts its own native attributes, handlers, ref, and `render` composition. `Popup.ref` points to the alert content element. `Title` and `Description` establish the accessible relationships; provide `aria-label` on `Popup` when omitting a title.

The confirmation action is application content, not an exported part. Use `Close` with a synchronous handler or a `Button` with controlled open state for asynchronous confirmation.

## Controlled state

Pass `open` and update it with `onOpenChange` to own the same dialog's visibility in React state. The callback receives the requested boolean and upstream event details, including `reason`, `event`, and `cancel()`. Call `eventDetails.cancel()` to reject a requested change. `onOpenChangeComplete` runs after opening or closing transitions finish.

```tsx theme={null}
import { useState } from 'react';
import { Button } from 'twenty-ui/primitives/input';
import { AlertDialog } from 'twenty-ui/primitives/surfaces';

type DeleteConfirmationProps = { onDelete: () => void };

export const DeleteConfirmation = ({ onDelete }: DeleteConfirmationProps) => {
  const [open, setOpen] = useState(false);

  return (
    <AlertDialog.Root open={open} onOpenChange={setOpen}>
      <AlertDialog.Trigger
        render={<Button variant="solid">Delete record</Button>}
      />
      <AlertDialog.Portal>
        <AlertDialog.Backdrop />
        <AlertDialog.Viewport>
          <AlertDialog.Popup>
            <AlertDialog.Header>
              <AlertDialog.Title>Delete this record?</AlertDialog.Title>
              <AlertDialog.Description>
                This record will be permanently deleted. This action cannot be
                undone.
              </AlertDialog.Description>
            </AlertDialog.Header>
            <AlertDialog.Footer>
              <AlertDialog.Close render={<Button>Cancel</Button>} />
              <AlertDialog.Close
                onClick={onDelete}
                render={<Button color="danger">Delete</Button>}
              />
            </AlertDialog.Footer>
          </AlertDialog.Popup>
        </AlertDialog.Viewport>
      </AlertDialog.Portal>
    </AlertDialog.Root>
  );
};
```

For asynchronous confirmation, use a `Button` with your action handler instead of `AlertDialog.Close`. Keep `open` true while the action is pending, call `setOpen(false)` after it succeeds, and show an error inside the dialog if it fails.

## Compose with buttons

Use `render` to give the trigger and close controls Twenty UI button styling. The dialog parts supply their interaction handlers and refs to the buttons.

```tsx theme={null}
import { Button } from 'twenty-ui/primitives/input';
import { AlertDialog } from 'twenty-ui/primitives/surfaces';

type DeleteConfirmationProps = { onDelete: () => void };

export const DeleteConfirmation = ({ onDelete }: DeleteConfirmationProps) => (
  <AlertDialog.Root>
    <AlertDialog.Trigger
      render={<Button variant="solid">Delete record</Button>}
    />
    <AlertDialog.Portal>
      <AlertDialog.Backdrop />
      <AlertDialog.Viewport>
        <AlertDialog.Popup>
          <AlertDialog.Header>
            <AlertDialog.Title>Delete this record?</AlertDialog.Title>
            <AlertDialog.Description>
              This record will be permanently deleted. This action cannot be
              undone.
            </AlertDialog.Description>
          </AlertDialog.Header>
          <AlertDialog.Footer>
            <AlertDialog.Close render={<Button>Cancel</Button>} />
            <AlertDialog.Close
              onClick={onDelete}
              render={<Button color="danger">Delete</Button>}
            />
          </AlertDialog.Footer>
        </AlertDialog.Popup>
      </AlertDialog.Viewport>
    </AlertDialog.Portal>
  </AlertDialog.Root>
);
```

Keep each action as a single interactive control. If you wrap `Button` in your own component, [forward the supplied props and ref](/ui/primitives/overview#custom-components).

## Detached triggers and imperative actions

Create a handle once with `AlertDialog.createHandle<Payload>()` and pass it to `handle` on `Root` and each detached `Trigger`. A trigger's typed `payload` is available to the root's child render function. A handle also supports `open(triggerId)`, `openWithPayload(payload)`, `close()`, and the `isOpen` getter while its root is mounted. Pass a matching trigger ID to `open`, or `null` to open without a trigger. Call imperative methods from event handlers or effects.

`Root.actionsRef` exposes `close()` and `unmount()`. For an externally controlled closing animation, call `eventDetails.preventUnmountOnClose()` in `onOpenChange`, then call `actionsRef.current?.unmount()` after the animation finishes. The regular styled parts manage their own transitions without these imperative actions.

## Sizing and portals

`Popup.size` accepts `sm`, `md`, `lg`, `xl`, and `fullscreen`, and defaults to `md`. Size and appearance belong to the AlertDialog surface and do not have to match Dialog presets.

`Portal.container` defaults to the nearest theme's portal container. Without one, Base UI uses its default portal destination, normally `document.body`. An explicit element, shadow root, or ref overrides that destination. An explicit `null` defers mounting until a container is available. Base UI resolves a ref whose `current` is `null` using its default destination; use `container={null}` when mounting must wait.

Portaled content retains the theme context. `Portal` and `Viewport` inherit the provided text direction unless you set `dir` explicitly. Set `Portal.keepMounted` to retain mounted content and form state while closed.

## Focus and dismissal

The alert traps focus, blocks outside interaction, and locks page scrolling while open. Escape requests closure; clicking outside does not. To prevent Escape dismissal, cancel the `escape-key` change in `onOpenChange`. Always provide a visible Cancel or Close action.

By default, focus moves to the first tabbable control, or to the popup for a touch opening. Put the least destructive action first, or use `Popup.initialFocus` to select it. Focus returns to the trigger or previously focused element when the alert closes. Use `Popup.finalFocus` when a successful action removes that target. Both focus props accept a boolean, element ref, or interaction-type callback according to the upstream contract.

## Props

The reference is generated from the public component types. Native attributes, including accessible names and event handlers, are also accepted on parts that render elements.

### AlertDialog.Root

<ParamField body="Root.actionsRef" type="RefObject<DialogRootActions | null>">
  A ref to imperative actions.

  * `unmount`: Ends the closing phase of the alert dialog after an externally controlled closing animation finishes.
    Call `preventUnmountOnClose()` in `onOpenChange` first, otherwise the alert dialog completes closing on its own.
    Whether it leaves the DOM is decided by `keepMounted` on the portal.
  * `close`: Closes the alert dialog imperatively when called.
</ParamField>

<ParamField body="Root.children" type="ReactNode | PayloadChildRenderFunction<Payload>">
  The content of the dialog.
  This can be a regular React node or a render function that receives the `payload` of the active trigger.
</ParamField>

<ParamField body="Root.defaultOpen" type="boolean" default="false">
  Whether the dialog is initially open.

  To render a controlled dialog, use the `open` prop instead.
</ParamField>

<ParamField body="Root.defaultTriggerId" type="string | null">
  ID of the trigger that the dialog is associated with.
  This is useful in conjunction with the `defaultOpen` prop to create an initially open dialog.
</ParamField>

<ParamField body="Root.handle" type="AlertDialogHandle<Payload>">
  A handle to associate the alert dialog with a trigger.
  If specified, allows external triggers to control the alert dialog's open state.
  Can be created with the AlertDialog.createHandle() method.
</ParamField>

<ParamField body="Root.onOpenChange" type="((open: boolean, eventDetails: AlertDialogRootChangeEventDetails) => void)">
  Event handler called when the alert dialog is opened or closed.
</ParamField>

<ParamField body="Root.onOpenChangeComplete" type="((open: boolean) => void)">
  Event handler called after any animations complete when the dialog is opened or closed.
</ParamField>

<ParamField body="Root.open" type="boolean">
  Whether the dialog is currently open.
</ParamField>

<ParamField body="Root.triggerId" type="string | null">
  ID of the trigger that the dialog is associated with.
  This is useful in conjunction with the `open` prop to create a controlled dialog.
  There's no need to specify this prop when the dialog is uncontrolled (that is, when the `open` prop is not set).
</ParamField>

### AlertDialog.Trigger

<ParamField body="Trigger.className" type="string | ((state: DialogTriggerState) => string | undefined)">
  CSS class applied to the element, or a function that
  returns a class based on the component's state.
</ParamField>

<ParamField body="Trigger.handle" type="AlertDialogHandle<Payload>">
  A handle to associate the trigger with an alert dialog.
  Can be created with the AlertDialog.createHandle() method.
</ParamField>

<ParamField body="Trigger.id" type="string">
  ID of the trigger. In addition to being forwarded to the rendered element,
  it is also used to specify the active trigger for the dialog in controlled mode (with the DialogRoot `triggerId` prop).
</ParamField>

<ParamField body="Trigger.nativeButton" type="boolean" default="true">
  Whether the component renders a native `<button>` element when replacing it
  via the `render` prop.
  Set to `false` if the rendered element is not a button (for example, `<div>`).
</ParamField>

<ParamField body="Trigger.payload" type="Payload">
  A payload to pass to the dialog when it is opened.
</ParamField>

<ParamField body="Trigger.render" type="ReactElement<unknown, string | JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, DialogTriggerState>">
  Allows you to replace the component's HTML element
  with a different tag, or compose it with another component.

  Accepts a `ReactElement` or a function that returns the element to render.
</ParamField>

<ParamField body="Trigger.style" type="CSSProperties | ((state: DialogTriggerState) => CSSProperties | undefined)">
  Style applied to the element, or a function that
  returns a style object based on the component's state.
</ParamField>

### AlertDialog.Portal

<ParamField body="Portal.className" type="string | ((state: DialogPortalState) => string | undefined)">
  CSS class applied to the element, or a function that
  returns a class based on the component's state.
</ParamField>

<ParamField body="Portal.container" type="HTMLElement | ShadowRoot | RefObject<HTMLElement | ShadowRoot | null> | null">
  Portal destination. Omission uses the theme container or Base UI default; explicit `null` defers mounting. A ref with a null current value uses the Base UI default destination.
</ParamField>

<ParamField body="Portal.keepMounted" type="boolean" default="false">
  Keeps content mounted while the alert is closed.
</ParamField>

<ParamField body="Portal.render" type="ReactElement<unknown, string | JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, DialogPortalState>">
  Allows you to replace the component's HTML element
  with a different tag, or compose it with another component.

  Accepts a `ReactElement` or a function that returns the element to render.
</ParamField>

<ParamField body="Portal.style" type="CSSProperties | ((state: DialogPortalState) => CSSProperties | undefined)">
  Style applied to the element, or a function that
  returns a style object based on the component's state.
</ParamField>

### AlertDialog.Backdrop

<ParamField body="Backdrop.className" type="string | ((state: DialogBackdropState) => string | undefined)">
  CSS class applied to the element, or a function that
  returns a class based on the component's state.
</ParamField>

<ParamField body="Backdrop.forceRender" type="boolean" default="false">
  Whether the backdrop is forced to render even when nested.
</ParamField>

<ParamField body="Backdrop.render" type="ReactElement<unknown, string | JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, DialogBackdropState>">
  Allows you to replace the component's HTML element
  with a different tag, or compose it with another component.

  Accepts a `ReactElement` or a function that returns the element to render.
</ParamField>

<ParamField body="Backdrop.style" type="CSSProperties | ((state: DialogBackdropState) => CSSProperties | undefined)">
  Style applied to the element, or a function that
  returns a style object based on the component's state.
</ParamField>

### AlertDialog.Viewport

<ParamField body="Viewport.className" type="string | ((state: DialogViewportState) => string | undefined)">
  CSS class applied to the element, or a function that
  returns a class based on the component's state.
</ParamField>

<ParamField body="Viewport.render" type="ReactElement<unknown, string | JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, DialogViewportState>">
  Allows you to replace the component's HTML element
  with a different tag, or compose it with another component.

  Accepts a `ReactElement` or a function that returns the element to render.
</ParamField>

<ParamField body="Viewport.style" type="CSSProperties | ((state: DialogViewportState) => CSSProperties | undefined)">
  Style applied to the element, or a function that
  returns a style object based on the component's state.
</ParamField>

### AlertDialog.Popup

<ParamField body="Popup.className" type="string | ((state: DialogPopupState) => string | undefined)">
  CSS class applied to the element, or a function that
  returns a class based on the component's state.
</ParamField>

<ParamField body="Popup.finalFocus" type="boolean | RefObject<HTMLElement | null> | ((closeType: InteractionType) => boolean | void | HTMLElement | null)">
  Determines the element to focus when the dialog is closed.

  * `false`: Do not move focus.
  * `true`: Move focus based on the default behavior (trigger or previously focused element).
  * `RefObject`: Move focus to the ref element.
  * `function`: Called with the interaction type (`mouse`, `touch`, `pen`, or `keyboard`).
    Return an element to focus, `true` to use the default behavior, `null` to fall back to the default behavior, or `false`/`undefined` to do nothing.
</ParamField>

<ParamField body="Popup.initialFocus" type="boolean | RefObject<HTMLElement | null> | ((openType: InteractionType) => boolean | void | HTMLElement | null)">
  Determines the element to focus when the dialog is opened.
  By default, focus moves to the first tabbable element inside the popup, except when the dialog
  is opened by touch — then the popup itself is focused to avoid opening the virtual keyboard.

  * `false`: Do not move focus.
  * `true`: Move focus based on the default behavior (first tabbable element or popup).
  * `RefObject`: Move focus to the ref element.
  * `function`: Called with the interaction type (`mouse`, `touch`, `pen`, or `keyboard`).
    Return an element to focus, `true` to use the default behavior, `null` to fall back to the default behavior, or `false`/`undefined` to do nothing.
</ParamField>

<ParamField body="Popup.render" type="ReactElement<unknown, string | JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, DialogPopupState>">
  Allows you to replace the component's HTML element
  with a different tag, or compose it with another component.

  Accepts a `ReactElement` or a function that returns the element to render.
</ParamField>

<ParamField body="Popup.size" type="&#x22;fullscreen&#x22; | &#x22;lg&#x22; | &#x22;md&#x22; | &#x22;sm&#x22; | &#x22;xl&#x22;" default="md">
  Width of the alert, or `fullscreen` to fill the viewport.
</ParamField>

<ParamField body="Popup.style" type="CSSProperties | ((state: DialogPopupState) => CSSProperties | undefined)">
  Style applied to the element, or a function that
  returns a style object based on the component's state.
</ParamField>

### AlertDialog.Title

<ParamField body="Title.className" type="string | ((state: DialogTitleState) => string | undefined)">
  CSS class applied to the element, or a function that
  returns a class based on the component's state.
</ParamField>

<ParamField body="Title.render" type="ReactElement<unknown, string | JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, DialogTitleState>">
  Allows you to replace the component's HTML element
  with a different tag, or compose it with another component.

  Accepts a `ReactElement` or a function that returns the element to render.
</ParamField>

<ParamField body="Title.style" type="CSSProperties | ((state: DialogTitleState) => CSSProperties | undefined)">
  Style applied to the element, or a function that
  returns a style object based on the component's state.
</ParamField>

### AlertDialog.Description

<ParamField body="Description.className" type="string | ((state: DialogDescriptionState) => string | undefined)">
  CSS class applied to the element, or a function that
  returns a class based on the component's state.
</ParamField>

<ParamField body="Description.render" type="ReactElement<unknown, string | JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, DialogDescriptionState>">
  Allows you to replace the component's HTML element
  with a different tag, or compose it with another component.

  Accepts a `ReactElement` or a function that returns the element to render.
</ParamField>

<ParamField body="Description.style" type="CSSProperties | ((state: DialogDescriptionState) => CSSProperties | undefined)">
  Style applied to the element, or a function that
  returns a style object based on the component's state.
</ParamField>

### AlertDialog.Close

<ParamField body="Close.className" type="string | ((state: DialogCloseState) => string | undefined)">
  CSS class applied to the element, or a function that
  returns a class based on the component's state.
</ParamField>

<ParamField body="Close.nativeButton" type="boolean" default="true">
  Whether the component renders a native `<button>` element when replacing it
  via the `render` prop.
  Set to `false` if the rendered element is not a button (for example, `<div>`).
</ParamField>

<ParamField body="Close.render" type="ReactElement<unknown, string | JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, DialogCloseState>">
  Allows you to replace the component's HTML element
  with a different tag, or compose it with another component.

  Accepts a `ReactElement` or a function that returns the element to render.
</ParamField>

<ParamField body="Close.style" type="CSSProperties | ((state: DialogCloseState) => CSSProperties | undefined)">
  Style applied to the element, or a function that
  returns a style object based on the component's state.
</ParamField>

### AlertDialog.Header

<ParamField body="Header.render" type="ReactElement<unknown, string | JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, {}>">
  Allows you to replace the component's HTML element
  with a different tag, or compose it with another component.

  Accepts a `ReactElement` or a function that returns the element to render.
</ParamField>

### AlertDialog.Body

<ParamField body="Body.render" type="ReactElement<unknown, string | JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, {}>">
  Allows you to replace the component's HTML element
  with a different tag, or compose it with another component.

  Accepts a `ReactElement` or a function that returns the element to render.
</ParamField>

### AlertDialog.Footer

<ParamField body="Footer.render" type="ReactElement<unknown, string | JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, {}>">
  Allows you to replace the component's HTML element
  with a different tag, or compose it with another component.

  Accepts a `ReactElement` or a function that returns the element to render.
</ParamField>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.