# Dialog

> A modal dialog.

## Examples

### Basic

```vue
<script setup lang="ts">
const open = ref(false);
</script>

<template>
  <UiButton variant="secondary" @click="open = true">Open dialog</UiButton>

  <UiDialog v-model:open="open" title="Keyboard shortcuts" description="Work faster with these.">
    <ul class="demo-list">
      <li>Search <UiKbd keys="mod+k" size="small" /></li>
      <li>Save <UiKbd keys="mod+s" size="small" /></li>
      <li>Close <UiKbd keys="esc" size="small" /></li>
    </ul>
  </UiDialog>
</template>
```

### Form

The footer slot gets a `close` function.

```vue
<script setup lang="ts">
const open = ref(false);
const name = ref("Acme Inc.");
const toast = useToast();

function save(close: () => void) {
  toast.success(`Renamed to ${name.value}`);
  close();
}
</script>

<template>
  <UiButton @click="open = true">Rename workspace</UiButton>

  <UiDialog v-model:open="open" title="Rename workspace" size="sm">
    <UiInput v-model="name" label="Workspace name" autofocus />

    <template #footer="{ close }">
      <UiButton variant="ghost" @click="close">Cancel</UiButton>
      <UiButton @click="save(close)">Save</UiButton>
    </template>
  </UiDialog>
</template>
```

### Required step

With `dismissible` off, Escape, the backdrop and the × button do nothing; only your own buttons close it.

```vue
<script setup lang="ts">
const open = ref(false);
const accepted = ref(false);
</script>

<template>
  <UiButton variant="secondary" @click="open = true">Review terms</UiButton>

  <UiDialog
    v-model:open="open"
    title="We've updated our terms"
    description="Accept them to keep using your account."
    size="sm"
    :dismissible="false"
  >
    <UiCheckbox v-model="accepted" label="I accept the new terms" />

    <template #footer="{ close }">
      <UiButton :disabled="!accepted" @click="close">Continue</UiButton>
    </template>
  </UiDialog>
</template>
```

## API

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `title` | `string` | — | Heading, which names the dialog. |
| `label` | `string` | — | Accessible name when there's no visible `title`. |
| `description` | `string` | — | Supporting text, announced as the dialog's description. |
| `dismissible` | `boolean` | `true` | Whether Escape, the backdrop and the header's close button can close it. The slots' `close` always can. |
| `size` | `"lg" \| "md" \| "sm" \| "xl"` | `"md"` | Size hook, exposed as `data-dialog-size`. |
| `flush` | `boolean` | `false` | Layout hook for edge-to-edge content, exposed as `data-dialog-flush`. |
| `closeOnBackdrop` | `boolean` | `true` | Close when the backdrop is clicked. |
| `showCloseButton` | `boolean` | `true` | Render the header's close button. |
| `open` | `boolean` | `false` | Whether the dialog is open. |

| Event | Payload | Description |
| --- | --- | --- |
| `close` | `[]` | Closed by any means. |
| `update:open` | `[value: boolean]` | `v-model:open` update. |

| Slot | Props | Description |
| --- | --- | --- |
| `default` | `{ close: () => void; }` | Body content. Mounted on first open. |
| `header` | — | Replaces the title and description. |
| `footer` | `{ close: () => void; }` | Actions, e.g. buttons. |
| `close-icon` | — | Replaces the close button's icon. |

## Styling

- Parts (`[data-part="…"]`): `dialog`, `dialog-panel`, `dialog-header`, `dialog-header-text`, `dialog-title`, `dialog-description`, `dialog-close`, `dialog-body`, `dialog-footer`
- State attributes: `data-dialog-size`, `data-dialog-flush`

## Keyboard

| Keys     | Action                     |
| -------- | -------------------------- |
| `Escape` | Close (when `dismissible`) |
| `Tab`    | Cycle within the dialog    |

## Accessibility

- The page behind is inert and doesn't scroll; focus returns to the opener on close.
- Named by `title`, or `label` without one.
