Files
upstream-mirror e7da97194a
Some checks failed
App Prod-Parity E2E Dispatch / dispatch (push) Failing after 10s
CD Storybook UI / build (push) Failing after 3m25s
CD Storybook UI / dispatch (push) Has been skipped
CD deploy main / website-changed-files (push) Successful in 18m8s
CI Agent Skills / changed-files-check (push) Successful in 18m9s
CI Create App E2E minimal / changed-files-check (push) Successful in 24s
CI Create App / changed-files-check (push) Successful in 26s
CI Docs / changed-files-check (push) Successful in 26s
CI Emails / changed-files-check (push) Successful in 28s
CI Example App Hello World / changed-files-check (push) Successful in 23s
CI Front / changed-files-check (push) Has been skipped
CI Example App Postcard / changed-files-check (push) Successful in 27s
CI UI / changed-files-check (push) Has been skipped
CI Utils Test / changed-files-check (push) Successful in 45s
CI Twenty Apps / discover (push) Successful in 1m3s
CD deploy main / deploy-main (push) Failing after 3s
CI Agent Skills / agent-skills-validate (push) Has been skipped
CI Create App / create-app-test (lint) (push) Has been skipped
CI Emails / emails-test (push) Has been skipped
CI Front / front-task (lingui:compile) (push) Has been skipped
CI Front / front-task (lint) (push) Has been skipped
CI Example App Postcard / example-app-postcard (push) Has been skipped
CI UI / ui-task (lint) (push) Has been skipped
CI UI / ui-task (pack-size) (push) Has been skipped
CI UI / ui-task (size) (push) Has been skipped
CI UI / ui-task (test) (push) Has been skipped
CI UI / ui-task (typecheck) (push) Has been skipped
CI Utils Test / utils-test (push) Has been skipped
CI Twenty Apps / ${{ matrix.app.name }} (push) Has been skipped
CI Emails / ci-emails-status-check (push) Successful in 2s
CI Example App Hello World / ci-example-app-hello-world-status-check (push) Successful in 2s
CI Example App Postcard / ci-example-app-postcard-status-check (push) Successful in 3s
CI UI / ui-sb-test (push) Has been skipped
CI Utils Test / ci-utils-test-status-check (push) Successful in 2s
CI Twenty Apps / ci-twenty-apps-status-check (push) Successful in 2s
CI UI / ci-ui-status-check (push) Successful in 2s
CI Desktop / desktop (push) Failing after 1m8s
Push docs to Crowdin / Push documentation to Crowdin (push) Failing after 55s
Push translations to Crowdin / Extract and upload translations (push) Failing after 5s
Push website translations to Crowdin / Extract and upload website translations (push) Failing after 5s
CI Create App / create-app-test (test) (push) Has been skipped
CI Create App / create-app-test (typecheck) (push) Has been skipped
CI Docs / docs-lint (push) Has been skipped
CI Example App Hello World / example-app-hello-world (push) Has been skipped
CI Front / front-task (lingui:extract) (push) Has been skipped
CI Front / front-task (test) (push) Has been skipped
CI Front / front-task (typecheck) (push) Has been skipped
CI UI / ui-sb-build (push) Failing after 1m32s
CI Twenty Apps / ${{ matrix.app.name }} (${{ matrix.server-source }}) (push) Has been skipped
CI Agent Skills / agent-skills-publish (push) Has been skipped
CI Create App / ci-create-app-status-check (push) Successful in 2s
CI Agent Skills / agent-skills-remote-source (push) Has been skipped
CI Create App E2E minimal / create-app-e2e-minimal (push) Has been cancelled
CI E2E Main / e2e-test (push) Has been cancelled
CI Front / front-sb-build (push) Has been cancelled
CI Front / front-build (push) Has been cancelled
CI Create App E2E minimal / ci-create-app-e2e-minimal-status-check (push) Has been cancelled
CI E2E Main / ci-e2e-main-status-check (push) Has been cancelled
CI E2E Main / notify-main-ci-failure (push) Has been cancelled
CI E2E Main / qa-scout-comment (push) Has been cancelled
CI Front / front-sb-test (push) Has been cancelled
CI Front / front-sb-screenshots (push) Has been cancelled
CI Front / ci-front-status-check (push) Has been cancelled
DPA Sub-Processor Sync / sync-subprocessors (push) Failing after 3s
AI Catalog Sync / sync-catalog (push) Failing after 2s
snapshot of https://github.com/twentyhq/twenty.git (main, 2026-09-17; blobs > 131072B omitted)
2026-09-17 23:28:13 +05:00

163 lines
7.3 KiB
Plaintext

---
title: AlertDialog
description: Ask for confirmation before an action that needs an explicit decision.
---
import { StoryEmbed } from '/snippets/ui/StoryEmbed.mdx';
import AlertDialogReference from '/snippets/ui/generated/surfaces/alert-dialog.mdx';
Use `AlertDialog` for a decision that interrupts the current workflow, such as confirming deletion. It provides an accessible modal with a backdrop and focus management.
<StoryEmbed
storyId="ui-surfaces-alertdialog--documentation"
title="AlertDialog example"
height={440}
/>
## Anatomy
Keep the trigger and popup inside `AlertDialog.Root`. This tree shows the recommended layout for a confirmation dialog.
```text
AlertDialog.Root
├── AlertDialog.Trigger
└── 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. |
| `Popup` | Required | Renders the modal content with focus management. |
| `Title` | Recommended | Supplies the visible dialog 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. |
`Popup` includes the portal, backdrop, and viewport. Put content directly inside it and set `size`, `container`, and focus props on `Popup`. `Header`, `Body`, and `Footer` arrange content; `Title` and `Description` provide the accessible relationships.
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.
## Uncontrolled state
Use `defaultOpen` to set the initial visibility. The dialog owns subsequent changes from its trigger, close controls, and dismissal interactions.
```tsx
import { AlertDialog } from 'twenty-ui/primitives/surfaces';
type DeleteConfirmationProps = { onDelete: () => void };
export const DeleteConfirmation = ({ onDelete }: DeleteConfirmationProps) => (
<AlertDialog.Root defaultOpen={false}>
<AlertDialog.Trigger>Delete record</AlertDialog.Trigger>
<AlertDialog.Popup>
<AlertDialog.Header>
<AlertDialog.Title>Delete this record?</AlertDialog.Title>
<AlertDialog.Description>
This action cannot be undone.
</AlertDialog.Description>
</AlertDialog.Header>
<AlertDialog.Footer>
<AlertDialog.Close>Cancel</AlertDialog.Close>
<AlertDialog.Close onClick={onDelete}>Delete</AlertDialog.Close>
</AlertDialog.Footer>
</AlertDialog.Popup>
</AlertDialog.Root>
);
```
`defaultOpen` defaults to `false`, so it can be omitted. This example uses a synchronous confirmation callback and closes after the action runs.
## Controlled state
Pass `open` and update it with `onOpenChange` to own the same dialog's visibility in React state. The callback receives the next boolean and event details, including changes requested by the trigger and close controls.
```tsx
import { useState } from 'react';
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>Delete record</AlertDialog.Trigger>
<AlertDialog.Popup>
<AlertDialog.Header>
<AlertDialog.Title>Delete this record?</AlertDialog.Title>
<AlertDialog.Description>
This action cannot be undone.
</AlertDialog.Description>
</AlertDialog.Header>
<AlertDialog.Footer>
<AlertDialog.Close>Cancel</AlertDialog.Close>
<AlertDialog.Close onClick={onDelete}>Delete</AlertDialog.Close>
</AlertDialog.Footer>
</AlertDialog.Popup>
</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
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 color="danger">Delete record</Button>}
/>
<AlertDialog.Popup>
<AlertDialog.Header>
<AlertDialog.Title>Delete this record?</AlertDialog.Title>
<AlertDialog.Description>
This action cannot be undone.
</AlertDialog.Description>
</AlertDialog.Header>
<AlertDialog.Footer>
<AlertDialog.Close render={<Button variant="outline">Cancel</Button>} />
<AlertDialog.Close
onClick={onDelete}
render={<Button color="danger">Delete</Button>}
/>
</AlertDialog.Footer>
</AlertDialog.Popup>
</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).
## Sizing and portals
`Popup.size` defaults to `md`; see the reference for supported sizes. Use `container` to override the theme's portal container and `keepMounted` to retain mounted content when closed.
## Focus and dismissal
The dialog traps focus while open. Escape can dismiss it; clicking the backdrop does not. Always provide a visible Cancel or Close action. Keep the initial focus on the least destructive action, and preserve a meaningful return focus target when the action removes its trigger. Use `Popup.initialFocus` and `Popup.finalFocus` to customize focus behavior.
## 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.
<AlertDialogReference />