> Markdown version of [Dialog](https://vaadin.com/docs/next/components/dialog). Section index: [llms.txt](https://vaadin.com/docs/next/components/llms.txt)

# Dialog

Dialog is a small window that can be used to present information and user interface elements in an overlay.

**Lit** — `dialog-basic.ts`

```html
<vaadin-dialog
  header-title="New employee"
  .opened="${this.dialogOpened}"
  @closed="${() => {
    this.dialogOpened = false;
  }}"
>
  <vaadin-form-layout auto-responsive column-width="18rem" expand-fields>
    <vaadin-text-field label="First name"></vaadin-text-field>
    <vaadin-text-field label="Last name"></vaadin-text-field>
  </vaadin-form-layout>
  <div slot="footer">
    <vaadin-button @click="${this.close}">Cancel</vaadin-button>
    <vaadin-button theme="primary" @click="${this.close}">Add</vaadin-button>
  </div>
</vaadin-dialog>

<vaadin-button
  @click="${() => {
    this.dialogOpened = true;
  }}"
>
  Show dialog
</vaadin-button>
```

**Flow** — `DialogBasic.java`

```java
Dialog dialog = new Dialog();

dialog.setHeaderTitle("New employee");

FormLayout dialogLayout = createDialogLayout();
dialog.add(dialogLayout);

Button saveButton = createSaveButton(dialog);
Button cancelButton = new Button("Cancel", e -> dialog.close());
dialog.getFooter().add(cancelButton);
dialog.getFooter().add(saveButton);

Button button = new Button("Show dialog", e -> dialog.open());

add(dialog, button);
```

**React** — `dialog-basic.tsx`

```tsx
<Dialog
  headerTitle="New employee"
  opened={dialogOpened.value}
  onClosed={() => {
    dialogOpened.value = false;
  }}
  footer={
    <>
      <Button
        onClick={() => {
          dialogOpened.value = false;
        }}
      >
        Cancel
      </Button>
      <Button
        theme="primary"
        onClick={() => {
          dialogOpened.value = false;
        }}
      >
        Add
      </Button>
    </>
  }
>
  <FormLayout autoResponsive columnWidth="18rem" expandFields>
    <TextField label="First name" />
    <TextField label="Last name" />
  </FormLayout>
</Dialog>

<Button
  onClick={() => {
    dialogOpened.value = true;
  }}
>
  Show dialog
</Button>
```

## <a id="structure"></a>Structure

The Dialog component has static header and footer areas, and a scrolling content area between them. The header and footer are optional, and are hidden if empty and not explicitly enabled.

### <a id="header"></a>Header

The header contains an optional title element, and a slot next to it for custom header content, such as a close button.

If the dialog has a title (set via text or custom element), the header content slot is right-aligned. If no title is present, the header content slot is left-aligned.

**Lit** — `dialog-header.ts`

```html
<vaadin-dialog
  header-title="User details"
  .opened="${this.dialogOpened}"
  @closed="${() => {
    this.dialogOpened = false;
  }}"
>
  <div slot="header-content">
    <vaadin-button theme="tertiary" @click="${this.close}">
      <vaadin-icon icon="lumo:cross"></vaadin-icon>
    </vaadin-button>
  </div>
  <vaadin-form-layout auto-responsive column-width="18rem" expand-fields>
    <vaadin-text-field
      label="Name"
      value="${`${this.user?.firstName} ${this.user?.lastName}`}"
      readonly
      style="padding-top: 0;"
    ></vaadin-text-field>
    <vaadin-email-field
      label="Email"
      value="${ifDefined(this.user?.email)}"
      readonly
    ></vaadin-email-field>
    <vaadin-text-field
      label="Address"
      value="${this.addressDescription()}"
      readonly
    ></vaadin-text-field>
  </vaadin-form-layout>
</vaadin-dialog>
```

**Flow** — `DialogHeader.java`

```java
dialog.setHeaderTitle("User details");

Button closeButton = new Button(new Icon("lumo", "cross"),
        (e) -> dialog.close());
closeButton.addThemeVariants(ButtonVariant.TERTIARY);
dialog.getHeader().add(closeButton);
```

**React** — `dialog-header.tsx`

```tsx
<Dialog
  header-title="User details"
  opened={dialogOpened.value}
  onClosed={() => {
    dialogOpened.value = false;
  }}
  header={
    <Button theme="tertiary" onClick={close}>
      <Icon icon="lumo:cross" />
    </Button>
  }
>
  <FormLayout autoResponsive columnWidth="18rem" expandFields>
    <TextField
      label="Name"
      value={`${user.value?.firstName} ${user.value?.lastName}`}
      readonly
      style={{ paddingTop: 0 }}
    />
    <EmailField label="Email" value={user.value?.email} readonly />
    <TextField label="Address" value={addressDescription.value} readonly />
  </FormLayout>
</Dialog>
<Button onClick={open}>Show dialog</Button>
```

### <a id="footer"></a>Footer

Buttons for closure actions (e.g., *Save*, *Cancel*, *Delete*) should be placed in the footer. See the [Button](https://vaadin.com/docs/next/components/button.md#buttons-in-dialogs) component for guidelines for the placement of buttons in Dialogs. Footer content is right-aligned by default. Components can be left-aligned by applying a margin like so:

**Lit** — `dialog-footer.ts`

```html
<vaadin-dialog
  header-title="${`Delete user "${this.user?.firstName} ${this.user?.lastName}"?`}"
  .opened="${this.dialogOpened}"
  @closed="${() => {
    this.dialogOpened = false;
  }}"
>
  <div>Are you sure you want to delete this user permanently?</div>
  <div slot="footer">
    <vaadin-button theme="primary error" @click="${this.close}" style="margin-right: auto;">
      Delete
    </vaadin-button>
    <vaadin-button theme="tertiary" @click="${this.close}">Cancel</vaadin-button>
  </div>
</vaadin-dialog>
```

**Flow** — `DialogFooter.java`

```java
Button deleteButton = new Button("Delete", (e) -> dialog.close());
deleteButton.addThemeVariants(ButtonVariant.PRIMARY,
        ButtonVariant.ERROR);
deleteButton.getStyle().set("margin-right", "auto");
dialog.getFooter().add(deleteButton);

Button cancelButton = new Button("Cancel", (e) -> dialog.close());
cancelButton.addThemeVariants(ButtonVariant.TERTIARY);
dialog.getFooter().add(cancelButton);
```

**React** — `dialog-footer.tsx`

```tsx
<Dialog
  headerTitle={`Delete user "${user.value?.firstName} ${user.value?.lastName}"?`}
  opened={dialogOpened.value}
  onClosed={() => {
    dialogOpened.value = false;
  }}
  footer={
    <>
      <Button theme="primary error" onClick={close} style={{ marginRight: 'auto' }}>
        Delete
      </Button>
      <Button theme="tertiary" onClick={close}>
        Cancel
      </Button>
    </>
  }
>
  Are you sure you want to delete this user permanently?
</Dialog>
```

## <a id="modality"></a>Modality

A modal dialog blocks the user from interacting with the rest of the user interface while the dialog is open. A non-modal dialog, however, doesn’t block interaction. Dialogs are modal by default.

Use modal dialogs for:

- Displaying important information, like system errors;

- Requesting user input as part of a workflow, for example an edit dialog;

- Confirmation of irreversible actions, such as deleting data — Confirm Dialog is a convenient alternative for these use cases; and

- Breaking out sub-tasks into a separate user interface.

> **Important: Modal Parent Dialogs in Flow**
>
> See the [Technical](#technical) section for details on the behavior of modal dialogs in Vaadin Flow.

Use non-modal dialogs when the user needs access to the content below the dialog, and for less critical, optional, or support tasks.

**Lit**

```html
<vaadin-dialog modeless>...</vaadin-dialog>
```

**Flow**

```java
Dialog dialog = new Dialog();
dialog.setModality(ModalityMode.MODELESS);
```

**React**

```html
<Dialog modeless>...</Dialog>
```

Usually, non-modal dialogs should be draggable, so that the user can move them to access the user interface beneath.

> **Note:** Dialog is not modal in server side by default. In some use cases you may want to enable the server side modality.

```java
Dialog dialog = new Dialog();
dialog.setModality(ModalityMode.STRICT);
// Dialog needs to be added to layout
add(dialog);
```

## <a id="position"></a>Position

By default, dialogs open in the center of the viewport. A different positioning can be set programmatically. Dialogs can also be made draggable, allowing the end user to move them around.

The position of the dialog can be set using the `top` and `left` properties:

**Lit**

```html
<vaadin-dialog top="50px" left="50px">...</vaadin-dialog>
```

**Flow**

```java
Dialog dialog = new Dialog();
dialog.setTop("50px");
dialog.setLeft("50px");
```

**React**

```html
<Dialog top="50px" left="50px">...</Dialog>
```

### <a id="draggable"></a>Draggable

Dialogs can be made draggable, enabling the user to move them around using a pointing device.

By default, the outer edges of a dialog, as well as the space between its components, can be used to move the dialog around.

The default areas from which a dialog can be dragged depend on whether the built-in header is used if the built-in header or footer is used: they function as the default drag handles of the dialog. Without the built-in header, any empty space within the dialog functions can be used as a drag handle.

Any component contained within a dialog can be marked and used as a drag handle by applying the `draggable` class name to it. You can choose whether to make the component’s content draggable as well, or only the component itself.

**Lit** — `dialog-draggable.ts`

```html
<vaadin-dialog
  aria-label="Add note"
  draggable
  modeless
  .opened="${this.dialogOpened}"
  @closed="${() => {
    this.dialogOpened = false;
  }}"
>
  <div slot="header-content">
    <h2
      class="draggable"
      style="flex: 1; cursor: move; margin: 0; font-size: 1.5em; font-weight: bold; padding: var(--vaadin-gap-m) 0;"
    >
      Add note
    </h2>
  </div>
  <vaadin-form-layout auto-responsive column-width="18rem" expand-fields>
    <vaadin-text-field label="Title"></vaadin-text-field>
    <vaadin-text-area label="Description"></vaadin-text-area>
  </vaadin-form-layout>
  <div slot="footer">
    <vaadin-button @click="${this.close}">Cancel</vaadin-button>
    <vaadin-button theme="primary" @click="${this.close}">Add note</vaadin-button>
  </div>
</vaadin-dialog>
```

**Flow** — `DialogDraggable.java`

```java
dialog.setModality(ModalityMode.MODELESS);
dialog.setDraggable(true);

...

H2 headline = new H2("Add note");
headline.addClassName("draggable");
```

**React** — `dialog-draggable.tsx`

```tsx
<Dialog
  aria-label="Add note"
  draggable
  modeless
  opened={dialogOpened.value}
  onClosed={() => {
    dialogOpened.value = false;
  }}
  header={
    <h2
      className="draggable"
      style={{
        flex: 1,
        cursor: 'move',
        margin: 0,
        fontSize: '1.5em',
        fontWeight: 'bold',
        padding: 'var(--vaadin-gap-m) 0',
      }}
    >
      Add note
    </h2>
  }
  footerRenderer={() => (
    <>
      <Button onClick={close}>Cancel</Button>
      <Button theme="primary" onClick={close}>
        Add note
      </Button>
    </>
  )}
>
  <FormLayout autoResponsive columnWidth="18rem" expandFields>
    <TextField label="Title" />
    <TextArea label="Description" />
  </FormLayout>
</Dialog>
```

Make non-modal dialogs draggable so the user can interact with content that might otherwise be obscured by the Dialog. For example, a Dialog for taking notes or for adding widgets to a dashboard by dragging can offer a better experience by allowing the user to move the Dialog around.

Modal dialogs don’t benefit from being draggable, as their modality curtain (the dark overlay behind the dialog) obscures the underlying user interface.

### <a id="constraining-a-dialog-to-the-viewport"></a>Constraining a Dialog to the Viewport

By default, dialogs are not constrained to the viewport, which means they can become partially invisible when dragging the dialog or when resizing the viewport. To prevent this, set the `keepInViewport` property to `true` to always keep the dialog fully visible within the viewport. Note that enabling this option may also adjust the dialog’s size and position if it can not fit the viewport otherwise.

**Lit**

```html
<vaadin-dialog keep-in-viewport>...</vaadin-dialog>
```

**Flow**

```java
Dialog dialog = new Dialog();
dialog.setKeepInViewport(true);
```

**React**

```html
<Dialog keepInViewport>...</Dialog>
```

## <a id="size"></a>Size

The Dialog size can be set with the width and height on the Dialog itself. You can also set the size of the content of Dialog, whereby the Dialog scales to accommodate it. In both cases, the Dialog can also be made resizable.

**Lit**

```html
<vaadin-dialog width="400px" height="200px">...</vaadin-dialog>
```

**Flow**

```java
Dialog dialog = new Dialog();
dialog.setWidth("400px");
dialog.setHeight("200px");
```

**React**

```html
<Dialog width="400px" height="200px">...</Dialog>
```

### <a id="resizable"></a>Resizable

The Dialog can be configured to allow the end user to resize it by dragging from its edges.

Dialogs containing dynamic content or plenty of information, such as complex forms or Grids, may benefit from being resizable. This offers the user some flexibility with how much data is visible at once. It also gives the user control over which part of the underlying user interface is obscured.

Dialogs that contain very little or compact information don’t need to be resizable.

**Lit** — `dialog-resizable.ts`

```html
<vaadin-dialog
  class="resizable-dialog"
  header-title="Employee list"
  resizable
  draggable
  .opened="${this.dialogOpened}"
  @closed="${() => {
    this.dialogOpened = false;
  }}"
>
  <vaadin-vertical-layout
    theme="spacing"
    style="max-width: 100%; min-width: 300px; height: 100%; align-items: stretch;"
  >
    <vaadin-grid .items="${this.people}">
      <vaadin-grid-column path="firstName" title="First name"></vaadin-grid-column>
      <vaadin-grid-column path="lastName" title="Last name"></vaadin-grid-column>
      <vaadin-grid-column path="email" title="Email"></vaadin-grid-column>
      <vaadin-grid-column path="profession" title="Profession"></vaadin-grid-column>
      <vaadin-grid-column path="membership" title="Membership"></vaadin-grid-column>
    </vaadin-grid>
  </vaadin-vertical-layout>
</vaadin-dialog>
```

**Flow** — `DialogResizable.java`

```java
dialog.setDraggable(true);
dialog.setResizable(true);
```

**React** — `dialog-resizable.tsx`

```tsx
<Dialog
  className="resizable-dialog"
  headerTitle="Employee list"
  resizable
  draggable
  opened={dialogOpened.value}
  onClosed={() => {
    dialogOpened.value = false;
  }}
>
  <VerticalLayout
    theme="spacing"
    style={{ maxWidth: '100%', minWidth: '300px', height: '100%', alignItems: 'stretch' }}
  >
    <Grid items={people.value}>
      <GridColumn path="firstName" title="First name" />
      <GridColumn path="lastName" title="Last name" />
      <GridColumn path="email" title="Email" />
      <GridColumn path="profession" title="Profession" />
      <GridColumn path="membership" title="Membership" />
    </Grid>
  </VerticalLayout>
</Dialog>
```

## <a id="closing"></a>Closing

Modal dialogs are closable in three ways: by pressing the `Esc` key; clicking outside the Dialog; or programmatically, for example through the click of a Button.

Providing an explicit button for closing a Dialog is recommended.

**Lit** — `dialog-closing.ts`

```html
<vaadin-dialog
  header-title="System maintenance"
  .opened="${this.dialogOpened}"
  @closed="${() => {
    this.dialogOpened = false;
  }}"
>
  <p style="max-width: 300px">
    System maintenance will begin at 3 PM. It is schedule to conclude at 5PM. We apologise for
    any inconvenience.
  </p>
  <div slot="footer">
    <vaadin-button @click="${this.close}">Close</vaadin-button>
  </div>
</vaadin-dialog>
```

**Flow** — `DialogClosing.java`

```java
Button closeButton = new Button("Close");
closeButton.addClickListener(e -> dialog.close());
```

**React** — `dialog-closing.tsx`

```tsx
<Dialog
  headerTitle="System maintenance"
  opened={dialogOpened.value}
  onClosed={() => {
    dialogOpened.value = false;
  }}
  footer={<Button onClick={close}>Close</Button>}
>
  <p style={{ maxWidth: '300px' }}>
    System maintenance will begin at 3 PM. It is schedule to conclude at 5PM. We apologise for
    any inconvenience.
  </p>
</Dialog>
```

## <a id="accessibility"></a>Accessibility

### <a id="focus"></a>Focus

When a modal dialog opens, keyboard focus moves into it automatically and stays inside: `Tab` and `Shift`+`Tab` cycle through the dialog’s content until it’s closed. When the dialog closes, focus returns to the element that had it before the dialog opened.

Non-modal dialogs also receive focus when opened, but they don’t trap it (since V25.3). Pressing `Tab` at the end of the dialog’s content moves focus out of the dialog and on through the rest of the page, so the user can keep working with the content below.

#### <a id="disabling-autofocus"></a>Disabling Autofocus (since V25.3)

For non-modal dialogs, the automatic focus move can be disabled so that focus stays where it was when the dialog opened. This is useful for auxiliary dialogs, such as a notes panel or a tool palette, that shouldn’t interrupt the user’s current task.

This setting only applies to non-modal dialogs. Modal dialogs always receive focus when opened.

**Lit**

```html
<vaadin-dialog modeless no-autofocus>...</vaadin-dialog>
```

**Flow**

```java
Dialog dialog = new Dialog();
dialog.setModality(ModalityMode.MODELESS);
dialog.setAutofocus(false);
```

**React**

```html
<Dialog modeless noAutofocus>...</Dialog>
```

> **Note:** The focus trap setting (`setFocusTrap` in Flow, `no-focus-trap` in the web component) is deprecated. Use the autofocus setting for non-modal dialogs instead.

### <a id="aria-role-and-accessible-name"></a>ARIA Role and Accessible Name

The dialog has the ARIA role `dialog` by default, and modal dialogs are marked with `aria-modal`. The role can be changed, for example to `alertdialog` for dialogs that interrupt a user’s workflow to communicate an important message and require a response.

The header title is used as the dialog’s accessible name. A dialog whose title is rendered with a custom element in the header (see [Header](#header)) doesn’t get an accessible name automatically. In that case, set `aria-label` or `aria-labelledby` on the dialog element.

**Lit**

```html
<vaadin-dialog role="alertdialog" header-title="Unsaved changes">...</vaadin-dialog>
```

**Flow**

```java
Dialog dialog = new Dialog();
dialog.setAriaRole("alertdialog");
dialog.setHeaderTitle("Unsaved changes");
```

**React**

```html
<Dialog role="alertdialog" headerTitle="Unsaved changes">...</Dialog>
```

## <a id="best-practices"></a>Best Practices

### <a id="use-sparingly"></a>Use Sparingly

Dialogs are disruptive by nature and should be used sparingly. Don’t use them to communicate non-essential information, such as success messages like "Logged in", "Copied", and so on. Instead, use [Notifications](https://vaadin.com/docs/next/components/notification.md) when appropriate.

### <a id="button-placement"></a>Button Placement

See [Buttons in Dialogs](https://vaadin.com/docs/next/components/button.md#buttons-in-dialogs).

## <a id="related-components"></a>Related Components

| Component                                                                   | Usage recommendations                                                 |
| --------------------------------------------------------------------------- | --------------------------------------------------------------------- |
| [Confirm Dialog](https://vaadin.com/docs/next/components/confirm-dialog.md) | Dialog for confirming user actions and decisions                      |
| [Popover](https://vaadin.com/docs/next/components/popover.md)               | A generic overlay whose position is anchored to an element in the UI. |

## <a id="technical"></a>Technical

### <a id="multiple-dialogs-and-strict-server-side-modality-in-flow"></a>Multiple Dialogs and Strict Server-side Modality in Flow

By default, opening multiple Dialog components in Strict modality mode simultaneously in Flow adds each subsequent Dialog as a child of the previous one.

Due to the [server-side modality mechanism in Flow](https://vaadin.com/docs/next/flow/advanced/server-side-modality.md#server-side-modality), this means that closing a modal Dialog automatically also closes all its children, that is, any subsequent Dialogs opened after the strictly modal.

This can be avoided by explicitly adding each Dialog to the UI before opening it:

```java
Dialog d1 = new Dialog();
d1.setModality(ModalityMode.STRICT);
Dialog d2 = new Dialog();
d2.setModality(ModalityMode.STRICT);
add(d1, d2);  // Add dialogs to the UI before opening
d1.open();
d2.open();
```

`EBCF8110-6074-4DAB-BE6B-662C813EDDC9`
