# Dialog

> A centered overlay on a scrim for a decision or a few fields people must finish before they continue, with a wide size for a large form filled in one pass.

Source: https://raft-design.botiverse.build/components/dialog. Generated from the current release; where it differs from what you remember, this page is right.

A dialog is a centered overlay on a scrim for something people must finish before they continue: a decision, or a small task of a few fields, such as creating a channel. It has a title, a body and at most two buttons. Its wide size holds a large form filled in one pass. To confirm an action, use [AlertDialog](https://raft-design.botiverse.build/components/alert-dialog.md).

```tsx
import {
  DialogBody,
  DialogClose,
  DialogContent,
  DialogFooter,
  DialogHeader,
  DialogTitle,
  Avatar,
  Banner,
  BannerDescription,
  Button,
  Combobox,
  ComboboxContent,
  ComboboxControl,
  ComboboxInput,
  ComboboxItem,
  ComboboxItemIndicator,
  ComboboxList,
  Field,
  FieldDescription,
  FieldLabel,
  Input,
  SegmentedControl,
  SegmentedControlItem,
  SegmentedControlLabel,
  Textarea,
} from "@botiverse/raft-ui";
import { Hash, Lock, Search } from "lucide-react";

const members = [
  { id: "atlas", name: "Atlas", kind: "agent" },
  { id: "avery", name: "Avery", kind: "human" },
  { id: "mira", name: "Mira", kind: "agent" },
] as const;

type DialogMember = (typeof members)[number];

const defaultMembers = [members[0], members[2]];

function isSameMember(item: DialogMember, value: DialogMember) {
  return item.id === value.id;
}

function getMemberLabel(member: DialogMember) {
  return member.name;
}

function CreateChannelDialogParts() {
  return (
    <>
      <DialogHeader>
        <DialogTitle>Create Channel</DialogTitle>
        <DialogClose />
      </DialogHeader>
      <DialogBody className="grid gap-4">
        <Banner status="warning" size="sm">
          <BannerDescription className="grid gap-2">
            <span className="font-medium">
              The name <span className="font-mono font-bold">#archive</span> is held by an archived
              channel.
            </span>
            <span>Unarchive it to keep its history, or choose a different name.</span>
            <span className="flex flex-wrap justify-end gap-2">
              <Button type="button" variant="accent" size="md">
                Unarchive
              </Button>
              <Button type="button" variant="outline" size="md">
                Change name
              </Button>
            </span>
          </BannerDescription>
        </Banner>
        <Field>
          <FieldLabel htmlFor="dialog-create-channel-name" required>
            Name
          </FieldLabel>
          <Input id="dialog-create-channel-name" placeholder="e.g. ai-research" />
        </Field>
        <Field>
          <FieldLabel htmlFor="dialog-create-channel-description">Description</FieldLabel>
          <Textarea
            id="dialog-create-channel-description"
            placeholder="What is this channel about?"
            className="min-h-16"
          />
        </Field>
        <Field>
          <FieldLabel>Visibility</FieldLabel>
          <SegmentedControl defaultValue="public" aria-label="Channel visibility">
            <SegmentedControlItem value="public">
              <Hash />
              <SegmentedControlLabel>Public</SegmentedControlLabel>
            </SegmentedControlItem>
            <SegmentedControlItem value="private">
              <Lock />
              <SegmentedControlLabel>Private</SegmentedControlLabel>
            </SegmentedControlItem>
          </SegmentedControl>
        </Field>
        <Field>
          <FieldLabel>Members</FieldLabel>
          <Combobox<DialogMember, true>
            multiple
            autoHighlight
            items={members}
            defaultValue={defaultMembers}
            isItemEqualToValue={isSameMember}
            itemToStringLabel={getMemberLabel}
          >
            <ComboboxControl className="w-full">
              <Search className="text-foreground-muted" />
              <ComboboxInput
                aria-label="Search members"
                placeholder="Search members by name"
                suppressPasswordManager
              />
            </ComboboxControl>
            <ComboboxContent className="w-(--anchor-width)">
              <ComboboxList className="max-h-none">
                {(member: DialogMember) => (
                  <ComboboxItem key={member.id} value={member}>
                    <span className="flex min-w-0 items-center gap-2">
                      <Avatar type={member.kind === "agent" ? "agent" : "human"} size="xs" />
                      <span className="min-w-0 truncate">{member.name}</span>
                    </span>
                    <ComboboxItemIndicator />
                  </ComboboxItem>
                )}
              </ComboboxList>
            </ComboboxContent>
          </Combobox>
          <FieldDescription>
            Select the people and agents that should join immediately.
          </FieldDescription>
        </Field>
      </DialogBody>
      <DialogFooter>
        <DialogClose render={<Button variant="outline" />}>Cancel</DialogClose>
        <Button variant="accent">Create</Button>
      </DialogFooter>
    </>
  );
}

export function CreateChannelDialogContent() {
  return (
    <DialogContent>
      <CreateChannelDialogParts />
    </DialogContent>
  );
}
```

## When to use

| Situation                                                                            | Use                                                                                                                                             |
| ------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| A small task in 1 to 5 fields (Create Channel)                                       | Dialog                                                                                                                                          |
| A large form filled in one pass: registering or editing an app, configuring an agent | Dialog with `size="wide"`                                                                                                                       |
| Task details                                                                         | A workspace overlay on Dialog, 960px wide and full screen on a phone, outside the four sizes ([Tasks](https://raft-design.botiverse.build/patterns/tasks.md)) |
| Confirming an action that cannot be undone, or that interrupts                       | [AlertDialog](https://raft-design.botiverse.build/components/alert-dialog.md)                                                                                                  |
| An action that can be reversed in place                                              | No dialog: do it; when a [Toast](https://raft-design.botiverse.build/components/toast.md) offers Undo is in [Feedback](https://raft-design.botiverse.build/patterns/feedback.md#confirming)         |
| Details or settings people look at and edit for a while                              | [Drawer](https://raft-design.botiverse.build/components/drawer.md)                                                                                                                   |

Which overlay fits which job is in [Choosing a component](https://raft-design.botiverse.build/components.md#overlays).

## Anatomy

- `Dialog`: the root. Owns the open state. Required.
- `DialogTrigger`: the button that opens it.
- `DialogContent`: the centered surface, portaled, with the scrim (`DialogOverlay`) behind it. Required.
- `DialogHeader`: the title row, with an optional `DialogClose` at its end. The × is pulled out so its icon box, not the button, ends on the dialog's 20px margin ([Alignment](https://raft-design.botiverse.build/foundations/alignment.md#the-ends-of-a-header)).
- `DialogTitle`: the title. Required.
- `DialogDescription`: a sentence under the title or in the body.
- `DialogBody`: the content. It scrolls when the dialog reaches the window height.
- `DialogFooter`: the buttons, aligned to the end.
- `DialogClose`: closes the dialog. Without children it is the × icon button; with `render` it turns a Cancel button into a close button.
- `DialogNav`: the section list of a wide dialog.
- `DialogSurface`: the dialog's frame without Base UI behind it, for a centered modal whose app owns the backdrop, Esc and focus, such as search.
- `DialogPortal` and `DialogOverlay`: lower-level parts.

## Variants

Pick the size by what the dialog holds, not by what looks right. The four sizes are far enough apart that each holds one kind of content (cindyz, 2026-10-21):

| Variant               | Width | Use for                                                                                                                                                                                                                                                         |
| --------------------- | ----- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `size="sm"`           | 400px | A decision: every confirmation and acknowledgement, including one with a few options to choose from or a short list of what it affects (Reset Agent, Change Visibility, the restart options). It is the width of [AlertDialog](https://raft-design.botiverse.build/components/alert-dialog.md) |
| `size="md"` (default) | 448px | A small task: 1 to 5 fields, a list to pick from, a short help text that is only read (Create Channel, Add Members, role help)                                                                                                                                  |
| `size="lg"`           | 640px | Content that needs width: a list with several columns, a command or code, key-value rows, a long text to read, a flow of steps (Connect Computer, a computer's release notes)                                                                                   |
| `size="wide"`         | 896px | The large form dialog, in sections, with a fixed height of 760px or the window height less 32px, whichever is smaller                                                                                                                                           |

- Every confirmation is one width, 400px, whether it is built on Dialog or AlertDialog. A confirmation whose content no longer fits 400px isn't a confirmation any more: it is a small task, at `md`.
- `sm`, `md` and `lg` are the small dialog: its height follows its content, up to the window less 32px, and a click on the scrim closes it. `wide` is the large form dialog.
- Set the width with `size` only. Product code never passes its own `max-w-*` to `DialogContent`. Content that fits none of the four sizes isn't a dialog: make it a page or a [Drawer](https://raft-design.botiverse.build/components/drawer.md).
- Only these overlays have a width outside the four sizes, each set by its own rule. Nothing else may add one:
  - Task details, 960px: a workspace overlay ([Tasks](https://raft-design.botiverse.build/patterns/tasks.md)).
  - Search, 720px, on `DialogSurface`, its top edge over the top bar's field ([Search](https://raft-design.botiverse.build/components/search.md)).
  - The showcase frame, 720px wide and about 520px high, shared by steps 3 to 5 of onboarding and the Upgrade to Pro dialog, and used by nothing else ([Onboarding](https://raft-design.botiverse.build/products/raft-chat/onboarding.md)).
  - [AnnouncementDialog](https://raft-design.botiverse.build/components/announcement-dialog.md), 576px: its picture and one-paragraph text read best there; at 640px the text runs past 80 characters a line.
  - An attachment preview, as wide as the file needs, up to 768px.
- On a narrow screen every size is as wide as itself or the window less 32px, whichever is smaller, so at 390px each one is 358px wide. Its height and the wide dialog's sections are in [Behavior](#behavior).

The large form dialog uses `bar` on `DialogHeader`, `DialogBody` and `DialogFooter`: the header and footer stay in place and the body scrolls between them. The body holds `DialogNav` on the left, a `line-seam` after it, and one [FormSection](https://raft-design.botiverse.build/components/form-section.md) per section on the right. Its structure and rules are in [Forms](https://raft-design.botiverse.build/patterns/forms.md#the-large-form-dialog).

## Behavior

- A centered dialog appears and disappears without animation, always over the scrim ([Motion](https://raft-design.botiverse.build/foundations/motion.md#usage)). On a phone a dialog with fields is a sheet that slides up instead ([On a phone](#on-a-phone)).
- Esc, × and Cancel close a dialog. A click on the scrim closes a small dialog.
- Don't close a large form dialog on a click outside it: pass `disablePointerDismissal` on `Dialog`, so a half-filled form isn't lost to a stray click.
- A centered dialog on a narrow screen keeps a 16px margin on each side and never grows taller than the window less 32px.
- Below 768px the wide dialog hides `DialogNav` and the sections follow one another.
- A dialog opened from a dialog or a sheet draws its own, lighter scrim over the one below ([Stacked overlays](https://raft-design.botiverse.build/foundations/elevation.md#stacked-overlays)). Render it inside the first one and this happens by itself. `layer={1}` is only for a dialog rendered outside the first one's tree: it lifts the dialog and its scrim above the first.

## On a phone

Below 768px a dialog stays centered unless it has several fields, a long list or steps, in which case it becomes a sheet (stdrc and Artea, 2026-10-21). On a desktop and a tablet every dialog stays centered.

| What the dialog holds                                                                                                                                               | On a phone                                                                                                     |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- |
| A decision: a statement and buttons, at most a few fixed choices, nothing typed (every confirmation; archive, stop, reset)                                          | The centered dialog, as on a desktop                                                                           |
| One input or one text box and its buttons: a confirmation that asks for a typed name, naming a section, editing a display name or a description, a reason to reject | The centered dialog, as on a desktop. While the keyboard is open it moves up, so the keyboard doesn't cover it |
| Several fields, a long or searchable list to pick from, or steps: forms, pickers, wizards                                                                           | A sheet 90% of the screen tall                                                                                 |
| Content that is only read: role help, release notes, an app's details. It is short information, so it stays a dialog                                                | The centered dialog, as on a desktop                                                                           |

The sheet:

- Rises from the bottom over the scrim, with `radius-dialog` on its top corners. The strip of page left above it shows that it is a layer over the page, not a new page.
- Its head is a pushed page's head ([Navigation](https://raft-design.botiverse.build/patterns/navigation.md)): × at the start, the title, and the dialog's one commit button at the end, at size `md` with the same color and words as on a desktop. It has no footer: × is Cancel. In a flow of steps the button at the end is the step's (Next, then the last step's action), and × still closes.
- The body scrolls under the head and keeps the phone's 16px margin and the home indicator's inset at the bottom.
- × and Esc close it. A tap on the scrim doesn't, so a half-filled form isn't lost to a stray tap, as with a large form dialog on a desktop. When something has been typed, ask before closing.
- Dragging the sheet down to close it is planned, for when the sheet moves into raft-ui on top of Drawer's drag.
- It slides up as it opens, like every bottom sheet ([Motion](https://raft-design.botiverse.build/foundations/motion.md#usage)).

Raft Chat builds these forms in the app for now (`NarrowDialog` in slock); they move into raft-ui as a phone presentation of Dialog.

## Content

- Title the dialog with the words of the button that opened it, or Edit and the item's name. Label its main button with the action it performs, without the object: usually the title's verb (Create Channel → Create); an Edit title's button is Save, and the other one Cancel ([Writing](https://raft-design.botiverse.build/content/writing.md#actions-and-their-dialogs)).
- Set body text in `foreground-muted`, below a title in `foreground`. Their type styles are in [Typography](https://raft-design.botiverse.build/foundations/typography.md).

## Accessibility

- Dialog wraps the Base UI Dialog. It provides the `dialog` role, the focus trap, Esc and focus return to the trigger.
- Give every dialog a `DialogTitle`. It becomes the dialog's accessible name, and it is what a screen reader announces on open.
- `DialogDescription` becomes the dialog's description.
- The × of `DialogClose` is labeled "Close". Pass `aria-label` to change it.
- `DialogSurface` has no behavior of its own. The app that uses it must add the `dialog` role, `aria-modal`, a name, the focus trap, Esc and the scrim.

## Rules

- Put at most two buttons in the footer: Cancel on the left (`variant="ghost"`), the confirm button on the right.
- Make the confirm button pink (`variant="primary"`) when it does something. Color it by its consequence when it interrupts or can't be undone ([AlertDialog](https://raft-design.botiverse.build/components/alert-dialog.md#variants)).
- Put anything people must read before they act in a [Banner](https://raft-design.botiverse.build/components/banner.md) inside the body ([Feedback](https://raft-design.botiverse.build/patterns/feedback.md#errors-by-scope)).
- Pad every size by 20px. Its width comes from `size` ([Variants](#variants)), never from a class of your own.
- Don't pass `overlay={false}` in product code: every centered dialog has the scrim, without exception.

## API

### Dialog

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `actionsRef` | `RefObject<DialogRootActions \| null>` |  | A ref to imperative actions. - `unmount`: Manually unmounts the dialog. Call this after any externally controlled closing animation finishes. - `close`: Closes the dialog imperatively when called. |
| `children` | `ReactNode \| PayloadChildRenderFunction<unknown>` |  | The content of the dialog. This can be a regular React node or a render function that receives the `payload` of the active trigger. |
| `defaultOpen` | `boolean` | `false` | Whether the dialog is initially open. |
| `defaultTriggerId` | `string` |  | 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. |
| `disablePointerDismissal` | `boolean` | `false` | Whether to prevent the dialog from closing on outside presses. For non-modal dialogs, this also prevents the dialog from closing when focus moves outside of it. |
| `handle` | `BaseDialog.Handle<unknown>` |  | A handle to associate the dialog with a trigger. If specified, allows external triggers to control the dialog's open state. Can be created with the Dialog.createHandle() method. |
| `modal` | `boolean \| "trap-focus"` | `true` | Determines if the dialog enters a modal state when open. - `true`: user interaction is limited to just the dialog: focus is trapped, document page scroll is locked, and pointer interactions on outside elements are disabled. - `false`: user interaction with the rest of the document is allowed. - `'trap-focus'`: focus is trapped inside the dialog, but document page scroll is not locked and pointer interactions outside of it remain enabled. |
| `onOpenChange` | `(open: boolean, eventDetails: BaseDialog.Root.ChangeEventDetails) => void` |  | Event handler called when the dialog is opened or closed. |
| `onOpenChangeComplete` | `(open: boolean) => void` |  | Event handler called after any animations complete when the dialog is opened or closed. |
| `open` | `boolean` |  | Whether the dialog is currently open. |
| `triggerId` | `string` |  | 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). |

### DialogBody

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `bar` | `boolean` | `false` | A pinned bar of a scrolling (`size="wide"`) dialog. |

Also takes the attributes of its element.

### DialogClose

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `children` | `ReactNode` |  |  |
| `size` | `"md" \| "lg" \| "xl" \| "icon-md" \| "icon-lg" \| DeprecatedButtonSize` | `"md"` | `md` (32px) and `icon-md` for rows, cards, banners, toolbars and panel headers; `lg` and `icon-lg` (the control height) for dialog footers, forms and beside a field; `xl` for a full-width call to action. The size follows the place: see Button › Size by place. |
| `variant` | `"primary" \| "accent" \| "warning" \| "danger" \| "default" \| "outline" \| "information" \| "muted" \| "success" \| "danger-secondary" \| "danger-outline" \| "ghost" \| "on-frame"` |  |  |
| `nativeButton` | `boolean` | `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>`). |
| `render` | `ReactElement \| ((props, state) => ReactElement)` |  | Allows you to replace the component's HTML element with a different tag, or compose it with another component. |

Also takes the attributes of its element.

### DialogContent

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `layer` | `0 \| 1` |  |  |
| `overlay` | `false \| DialogOverlayProps` |  |  |
| `portalProps` | `AlertDialogPortalProps` |  |  |
| `size` | `"sm" \| "md" \| "lg" \| "wide"` | `"md"` |  |
| `finalFocus` | `boolean \| RefObject<HTMLElement \| null> \| ((closeType: InteractionType) => boolean \| HTMLElement \| null \| void)` |  | Determines the element to focus when the dialog is closed. |
| `initialFocus` | `boolean \| RefObject<HTMLElement \| null> \| ((openType: InteractionType) => boolean \| HTMLElement \| null \| void)` |  | 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. |
| `render` | `ReactElement \| ((props, state) => ReactElement)` |  | Allows you to replace the component's HTML element with a different tag, or compose it with another component. |

Also takes the attributes of its element.

### DialogDescription

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `render` | `ReactElement \| ((props, state) => ReactElement)` |  | Allows you to replace the component's HTML element with a different tag, or compose it with another component. |

Also takes the attributes of its element.

### DialogFooter

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `bar` | `boolean` | `false` | A pinned bar of a scrolling (`size="wide"`) dialog. |

Also takes the attributes of its element.

### DialogHeader

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `bar` | `boolean` | `false` | A pinned bar of a scrolling (`size="wide"`) dialog. |

Also takes the attributes of its element.

### DialogNav

The section list of a wide (`size="wide"`) dialog, inside a `bar` body.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `render` | `ReactElement \| ((props, state) => ReactElement)` |  | Allows you to replace the component's HTML element with a different tag, or compose it with another component. |

Also takes the attributes of its element.

### DialogOverlay

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `layer` | `0 \| 1` |  |  |
| `forceRender` | `boolean` | `false` | Whether the backdrop is forced to render even when nested. |
| `render` | `ReactElement \| ((props, state) => ReactElement)` |  | Allows you to replace the component's HTML element with a different tag, or compose it with another component. |

Also takes the attributes of its element.

### DialogPortal

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `container` | `HTMLElement \| ShadowRoot \| RefObject<HTMLElement \| ShadowRoot \| null>` |  | A parent element to render the portal element into. |
| `keepMounted` | `boolean` | `false` | Whether to keep the portal mounted in the DOM while the popup is hidden. |
| `render` | `ReactElement \| ((props, state) => ReactElement)` |  | Allows you to replace the component's HTML element with a different tag, or compose it with another component. |

Also takes the attributes of its element.

### DialogSurface

The dialog's frame — the popover layer, the dialog radius, the seam ring and the float shadow — for a centred modal whose lifecycle the app owns (its own backdrop, Escape and focus handling). It neither positions nor animates itself: the host centres it, and a centred modal has no motion. DialogContent draws the same frame for a Base UI dialog.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `render` | `ReactElement \| ((props, state) => ReactElement)` |  | Allows you to replace the component's HTML element with a different tag, or compose it with another component. |

Also takes the attributes of its element.

### DialogTitle

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `render` | `ReactElement \| ((props, state) => ReactElement)` |  | Allows you to replace the component's HTML element with a different tag, or compose it with another component. |

Also takes the attributes of its element.

### DialogTrigger

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `handle` | `BaseDialog.Handle<unknown>` |  | A handle to associate the trigger with a dialog. Can be created with the Dialog.createHandle() method. |
| `id` | `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). |
| `nativeButton` | `boolean` | `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>`). |
| `payload` | `{}` |  | A payload to pass to the dialog when it is opened. |
| `render` | `ReactElement \| ((props, state) => ReactElement)` |  | Allows you to replace the component's HTML element with a different tag, or compose it with another component. |

Also takes the attributes of its element.

### AnnouncementDialog

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `actionsRef` | `RefObject<DialogRootActions \| null>` |  | A ref to imperative actions. - `unmount`: Manually unmounts the dialog. Call this after any externally controlled closing animation finishes. - `close`: Closes the dialog imperatively when called. |
| `children` | `ReactNode \| PayloadChildRenderFunction<unknown>` |  | The content of the dialog. This can be a regular React node or a render function that receives the `payload` of the active trigger. |
| `defaultOpen` | `boolean` | `false` | Whether the dialog is initially open. |
| `defaultTriggerId` | `string` |  | 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. |
| `disablePointerDismissal` | `boolean` | `false` | Whether to prevent the dialog from closing on outside presses. For non-modal dialogs, this also prevents the dialog from closing when focus moves outside of it. |
| `handle` | `BaseDialog.Handle<unknown>` |  | A handle to associate the dialog with a trigger. If specified, allows external triggers to control the dialog's open state. Can be created with the Dialog.createHandle() method. |
| `modal` | `boolean \| "trap-focus"` | `true` | Determines if the dialog enters a modal state when open. - `true`: user interaction is limited to just the dialog: focus is trapped, document page scroll is locked, and pointer interactions on outside elements are disabled. - `false`: user interaction with the rest of the document is allowed. - `'trap-focus'`: focus is trapped inside the dialog, but document page scroll is not locked and pointer interactions outside of it remain enabled. |
| `onOpenChange` | `(open: boolean, eventDetails: BaseDialog.Root.ChangeEventDetails) => void` |  | Event handler called when the dialog is opened or closed. |
| `onOpenChangeComplete` | `(open: boolean) => void` |  | Event handler called after any animations complete when the dialog is opened or closed. |
| `open` | `boolean` |  | Whether the dialog is currently open. |
| `triggerId` | `string` |  | 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). |

### AnnouncementDialogTrigger

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `handle` | `BaseDialog.Handle<unknown>` |  | A handle to associate the trigger with a dialog. Can be created with the Dialog.createHandle() method. |
| `id` | `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). |
| `nativeButton` | `boolean` | `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>`). |
| `payload` | `{}` |  | A payload to pass to the dialog when it is opened. |
| `render` | `ReactElement \| ((props, state) => ReactElement)` |  | Allows you to replace the component's HTML element with a different tag, or compose it with another component. |

Also takes the attributes of its element.

### AnnouncementDialogClose

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `children` | `ReactNode` |  |  |
| `size` | `"md" \| "lg" \| "xl" \| "icon-md" \| "icon-lg" \| DeprecatedButtonSize` | `"md"` | `md` (32px) and `icon-md` for rows, cards, banners, toolbars and panel headers; `lg` and `icon-lg` (the control height) for dialog footers, forms and beside a field; `xl` for a full-width call to action. The size follows the place: see Button › Size by place. |
| `variant` | `"primary" \| "accent" \| "warning" \| "danger" \| "default" \| "outline" \| "information" \| "muted" \| "success" \| "danger-secondary" \| "danger-outline" \| "ghost" \| "on-frame"` |  |  |
| `nativeButton` | `boolean` | `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>`). |
| `render` | `ReactElement \| ((props, state) => ReactElement)` |  | Allows you to replace the component's HTML element with a different tag, or compose it with another component. |

Also takes the attributes of its element.

## Changes

- 0.8.3 (Fixed): A `Dialog` or `AlertDialog` opened from a sheet or another dialog draws its own, lighter scrim, so it no longer sits undimmed on the surface below. A sheet opened from a dialog does the same; a sheet over a sheet is unchanged. Nesting follows the modal roots, as in Base UI, and a `modal={false}` parent doesn't count.
- 0.6.0 (Breaking Changes): **Props that no longer change anything are removed:** `Badge` `uppercase`; `Checkbox` `size`, `variant`, `color`; `Status` `pulse`, `attention` (status never animates); `Switch` / `SwitchThumb` `size`; `SidebarItem` `variant`; `SidebarItemCount` / `SidebarItemIndicator` `variant` and `appearance` (the count is always the pink sticker, the indicator the yellow @); `NotificationCenterActionButton` `variant`; `DrawerContent` `width` (one-go forms use the wide `Dialog`); `AppRailItemIndicator` `attention`; `AppRailItemAttention` `children`; `Steps` `size`, `track`, `renderIndicator`, `renderTraveler`; `FilePreviewBadge` `type`, `color`. Remove them at call sites.
- 0.5.28 (Added): Added the composable `AnnouncementDialog` through `raft-ui/wip`, built on existing Dialog and Button primitives, with a label, picture, scrolling body and fixed footer. Narrow dialogs stack both actions at full width.
