A RetroSearch Logo

Home - News ( United States | United Kingdom | Italy | Germany ) - Football scores

Search Query:

Showing content from https://vaadin.com/docs/latest/components/dialog below:

Dialog component | Vaadin components

  1. Docs
  2. Components
  3. Dialog

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

Open in a
new tab
Source code DialogBasic.java

package com.vaadin.demo.component.dialog; import com.vaadin.flow.component.button.Button; import com.vaadin.flow.component.button.ButtonVariant; import com.vaadin.flow.component.dialog.Dialog; import com.vaadin.flow.component.html.Div; import com.vaadin.flow.component.orderedlayout.FlexComponent; import com.vaadin.flow.component.orderedlayout.VerticalLayout; import com.vaadin.flow.component.textfield.TextField; import com.vaadin.flow.router.Route; @Route("dialog-basic") public class DialogBasic extends Div { public DialogBasic() { // tag::snippet[] Dialog dialog = new Dialog(); dialog.setHeaderTitle("New employee"); VerticalLayout 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); // end::snippet[] dialog.open(); // Center the button within the example getStyle().set("position", "fixed").set("top", "0").set("right", "0") .set("bottom", "0").set("left", "0").set("display", "flex") .set("align-items", "center").set("justify-content", "center"); } private static VerticalLayout createDialogLayout() { TextField firstNameField = new TextField("First name"); TextField lastNameField = new TextField("Last name"); VerticalLayout dialogLayout = new VerticalLayout(firstNameField, lastNameField); dialogLayout.setPadding(false); dialogLayout.setSpacing(false); dialogLayout.setAlignItems(FlexComponent.Alignment.STRETCH); dialogLayout.getStyle().set("width", "18rem").set("max-width", "100%"); return dialogLayout; } private static Button createSaveButton(Dialog dialog) { Button saveButton = new Button("Add", e -> dialog.close()); saveButton.addThemeVariants(ButtonVariant.LUMO_PRIMARY); return saveButton; } }

dialog-basic.tsx

import { useSignal } from '@vaadin/hilla-react-signals'; import { Button } from '@vaadin/react-components/Button.js'; import { Dialog } from '@vaadin/react-components/Dialog.js'; import { TextField } from '@vaadin/react-components/TextField.js'; import { VerticalLayout } from '@vaadin/react-components/VerticalLayout.js'; import dialogBasicStyles from './dialog-basic-styles'; function Example() { const dialogOpened = useSignal(true); return ( <> {/* tag::snippet[] */} <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> </> } > <VerticalLayout style={{ alignItems: 'stretch', width: '18rem', maxWidth: '100%' }}> <TextField label="First name" /> <TextField label="Last name" /> </VerticalLayout> </Dialog> <Button onClick={() => { dialogOpened.value = true; }} > Show dialog </Button> {/* end::snippet[] */} </> ); }

dialog-basic.ts

import '@vaadin/button'; import '@vaadin/dialog'; import '@vaadin/text-field'; import '@vaadin/vertical-layout'; import { css, html, LitElement } from 'lit'; import { customElement, state } from 'lit/decorators.js'; import { dialogFooterRenderer, dialogRenderer } from '@vaadin/dialog/lit.js'; import { applyTheme } from 'Frontend/generated/theme'; @customElement('dialog-basic') export class Example extends LitElement { static override styles = css` /* Center the button within the example */ :host { position: fixed; top: 0; right: 0; bottom: 0; left: 0; display: flex !important; align-items: center; justify-content: center; } `; protected override createRenderRoot() { const root = super.createRenderRoot(); // Apply custom theme (only supported if your app uses one) applyTheme(root); return root; } @state() private dialogOpened = true; protected override render() { return html` <!-- tag::snippet[] --> <vaadin-dialog header-title="New employee" .opened="${this.dialogOpened}" @closed="${() => { this.dialogOpened = false; }}" ${dialogRenderer(this.renderDialog, [])} ${dialogFooterRenderer(this.renderFooter, [])} ></vaadin-dialog> <vaadin-button @click="${() => { this.dialogOpened = true; }}" > Show dialog </vaadin-button> <!-- end::snippet[] --> `; } private renderDialog = () => html` <vaadin-vertical-layout style="align-items: stretch; width: 18rem; max-width: 100%;"> <vaadin-text-field label="First name"></vaadin-text-field> <vaadin-text-field label="Last name"></vaadin-text-field> </vaadin-vertical-layout> `; private renderFooter = () => html` <vaadin-button @click="${this.close}">Cancel</vaadin-button> <vaadin-button theme="primary" @click="${this.close}">Add</vaadin-button> `; private close() { this.dialogOpened = false; } }

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.

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.

Open in a
new tab
Source code DialogHeader.java

package com.vaadin.demo.component.dialog; import com.vaadin.demo.domain.DataService; import com.vaadin.demo.domain.Person; import com.vaadin.flow.component.button.Button; import com.vaadin.flow.component.button.ButtonVariant; import com.vaadin.flow.component.dialog.Dialog; import com.vaadin.flow.component.html.Div; import com.vaadin.flow.component.icon.Icon; import com.vaadin.flow.component.orderedlayout.FlexComponent; import com.vaadin.flow.component.orderedlayout.VerticalLayout; import com.vaadin.flow.component.textfield.EmailField; import com.vaadin.flow.component.textfield.TextField; import com.vaadin.flow.router.Route; @Route("dialog-header") public class DialogHeader extends Div { final Person user = DataService.getPeople().get(0); public DialogHeader() { Dialog dialog = new Dialog(); dialog.getElement().setAttribute("aria-label", "Add note"); VerticalLayout dialogLayout = createDialogLayout(dialog); dialog.add(dialogLayout); // tag::snippet1[] dialog.setHeaderTitle("User details"); Button closeButton = new Button(new Icon("lumo", "cross"), (e) -> dialog.close()); closeButton.addThemeVariants(ButtonVariant.LUMO_TERTIARY); dialog.getHeader().add(closeButton); // end::snippet1[] Button button = new Button("Show dialog", e -> dialog.open()); add(dialog, button); } private VerticalLayout createDialogLayout(Dialog dialog) { TextField nameField = new TextField("Name", user.getFullName(), "Full name"); nameField.setReadOnly(true); nameField.getStyle().set("padding-top", "0"); EmailField emailField = new EmailField("Email", user.getEmail()); emailField.setPlaceholder("email@company.com"); emailField.setReadOnly(true); String addressValue = String.format("%s, %s, %s", user.getAddress().getStreet(), user.getAddress().getCity(), user.getAddress().getCountry()); TextField addressField = new TextField("Address", addressValue, "Street XX, City, Country"); addressField.setReadOnly(true); VerticalLayout fieldLayout = new VerticalLayout(nameField, emailField, addressField); fieldLayout.setSpacing(false); fieldLayout.setPadding(false); fieldLayout.setAlignItems(FlexComponent.Alignment.STRETCH); fieldLayout.getStyle().set("width", "300px").set("max-width", "100%"); return fieldLayout; } }

dialog-header.tsx

import '@vaadin/icons'; import React, { useEffect } from 'react'; import { useComputed, useSignal } from '@vaadin/hilla-react-signals'; import { Button } from '@vaadin/react-components/Button.js'; import { Dialog } from '@vaadin/react-components/Dialog.js'; import { EmailField } from '@vaadin/react-components/EmailField.js'; import { Icon } from '@vaadin/react-components/Icon.js'; import { TextField } from '@vaadin/react-components/TextField.js'; import { VerticalLayout } from '@vaadin/react-components/VerticalLayout.js'; import { getPeople } from 'Frontend/demo/domain/DataService'; import type Person from 'Frontend/generated/com/vaadin/demo/domain/Person'; function Example() { const dialogOpened = useSignal(false); const user = useSignal<Person | undefined>(undefined); const open = () => { dialogOpened.value = true; }; const close = () => { dialogOpened.value = false; }; useEffect(() => { getPeople({ count: 1 }).then(({ people }) => { user.value = people[0]; }); }, []); const addressDescription = useComputed(() => { if (!user.value) { return ''; } const { address } = user.value; return `${address.street}, ${address.city}, ${address.country}`; }); return ( <> {/* tag::snippet[] */} <Dialog header-title="User details" opened={dialogOpened.value} onClosed={() => { dialogOpened.value = false; }} header={ <Button theme="tertiary" onClick={close}> <Icon icon="lumo:cross" /> </Button> } > <VerticalLayout theme="spacing" style={{ width: '300px', maxWidth: '100%', alignItems: 'stretch' }} > <VerticalLayout style={{ alignItems: 'stretch' }}> <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 /> </VerticalLayout> </VerticalLayout> </Dialog> <Button onClick={open}>Show dialog</Button> {/* end::snippet[] */} </> ); }

dialog-header.ts

import '@vaadin/button'; import '@vaadin/dialog'; import '@vaadin/email-field'; import '@vaadin/icon'; import '@vaadin/text-field'; import '@vaadin/vaadin-lumo-styles/vaadin-iconset'; import '@vaadin/vertical-layout'; import { html, LitElement } from 'lit'; import { customElement, state } from 'lit/decorators.js'; import { ifDefined } from 'lit/directives/if-defined.js'; import { dialogHeaderRenderer, dialogRenderer } from '@vaadin/dialog/lit.js'; import { getPeople } from 'Frontend/demo/domain/DataService'; import type Person from 'Frontend/generated/com/vaadin/demo/domain/Person'; import { applyTheme } from 'Frontend/generated/theme'; @customElement('dialog-header') export class Example extends LitElement { protected override createRenderRoot() { const root = super.createRenderRoot(); // Apply custom theme (only supported if your app uses one) applyTheme(root); return root; } @state() private dialogOpened = false; @state() private user: Person | undefined; protected override async firstUpdated() { const { people } = await getPeople({ count: 1 }); this.user = people[0]; } protected override render() { return html` <!-- tag::snippet[] --> <vaadin-dialog header-title="User details" .opened="${this.dialogOpened}" @closed="${() => { this.dialogOpened = false; }}" ${dialogHeaderRenderer( () => html` <vaadin-button theme="tertiary" @click="${this.close}"> <vaadin-icon icon="lumo:cross"></vaadin-icon> </vaadin-button> `, [] )} ${dialogRenderer(this.renderDialog, this.user)} ></vaadin-dialog> <!-- end::snippet[] --> <vaadin-button @click="${this.open}">Show dialog</vaadin-button> `; } private renderDialog = () => html` <vaadin-vertical-layout theme="spacing" style="width: 300px; max-width: 100%; align-items: stretch;" > <vaadin-vertical-layout style="align-items: stretch;"> <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-vertical-layout> </vaadin-vertical-layout> `; addressDescription() { if (!this.user) { return ''; } const { address } = this.user; return `${address.street}, ${address.city}, ${address.country}`; } private open() { this.dialogOpened = true; } private close() { this.dialogOpened = false; } }

Buttons for closure actions (e.g., Save, Cancel, Delete) should be placed in the footer. See the Button 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:

Open in a
new tab
Source code DialogFooter.java

package com.vaadin.demo.component.dialog; import com.vaadin.demo.domain.DataService; import com.vaadin.demo.domain.Person; import com.vaadin.flow.component.button.Button; import com.vaadin.flow.component.button.ButtonVariant; import com.vaadin.flow.component.dialog.Dialog; import com.vaadin.flow.component.html.Div; import com.vaadin.flow.router.Route; @Route("dialog-footer") public class DialogFooter extends Div { final Person user = DataService.getPeople().get(0); public DialogFooter() { Dialog dialog = new Dialog(); dialog.setHeaderTitle( String.format("Delete user \"%s\"?", user.getFullName())); dialog.add("Are you sure you want to delete this user permanently?"); // tag::snippet1[] Button deleteButton = new Button("Delete", (e) -> dialog.close()); deleteButton.addThemeVariants(ButtonVariant.LUMO_PRIMARY, ButtonVariant.LUMO_ERROR); deleteButton.getStyle().set("margin-right", "auto"); dialog.getFooter().add(deleteButton); Button cancelButton = new Button("Cancel", (e) -> dialog.close()); cancelButton.addThemeVariants(ButtonVariant.LUMO_TERTIARY); dialog.getFooter().add(cancelButton); // end::snippet1[] Button button = new Button("Show dialog", e -> dialog.open()); add(dialog, button); } }

dialog-footer.tsx

import React, { useEffect } from 'react'; import { useSignal } from '@vaadin/hilla-react-signals'; import { Button } from '@vaadin/react-components/Button.js'; import { Dialog } from '@vaadin/react-components/Dialog.js'; import { getPeople } from 'Frontend/demo/domain/DataService'; import type Person from 'Frontend/generated/com/vaadin/demo/domain/Person'; function Example() { const dialogOpened = useSignal(false); const user = useSignal<Person | undefined>(undefined); useEffect(() => { getPeople({ count: 1 }).then(({ people }) => { user.value = people[0]; }); }, []); function open() { dialogOpened.value = true; } function close() { dialogOpened.value = false; } return ( <> {/* tag::snippet[] */} <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> {/* end::snippet[] */} <Button onClick={open}>Show dialog</Button> </> ); }

dialog-footer.ts

import '@vaadin/button'; import '@vaadin/dialog'; import { html, LitElement } from 'lit'; import { customElement, state } from 'lit/decorators.js'; import { dialogFooterRenderer, dialogRenderer } from '@vaadin/dialog/lit.js'; import { getPeople } from 'Frontend/demo/domain/DataService'; import type Person from 'Frontend/generated/com/vaadin/demo/domain/Person'; import { applyTheme } from 'Frontend/generated/theme'; @customElement('dialog-footer') export class Example extends LitElement { protected override createRenderRoot() { const root = super.createRenderRoot(); // Apply custom theme (only supported if your app uses one) applyTheme(root); return root; } @state() private dialogOpened = false; @state() private user: Person | undefined; protected override async firstUpdated() { const { people } = await getPeople({ count: 1 }); this.user = people[0]; } protected override render() { return html` <!-- tag::snippet[] --> <vaadin-dialog header-title="${`Delete user "${this.user?.firstName} ${this.user?.lastName}"?`}" .opened="${this.dialogOpened}" @closed="${() => { this.dialogOpened = false; }}" ${dialogRenderer(() => html`Are you sure you want to delete this user permanently?`, [])} ${dialogFooterRenderer( () => html` <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> `, [] )} ></vaadin-dialog> <!-- end::snippet[] --> <vaadin-button @click="${this.open}">Show dialog</vaadin-button> `; } private open() { this.dialogOpened = true; } private close() { this.dialogOpened = false; } }

Padding

The content area’s built-in padding can be removed by applying the no-padding theme variant.

Open in a
new tab
Source code DialogNoPadding.java

package com.vaadin.demo.component.dialog; import com.vaadin.demo.domain.DataService; import com.vaadin.demo.domain.Person; import com.vaadin.flow.component.button.Button; import com.vaadin.flow.component.button.ButtonVariant; import com.vaadin.flow.component.dialog.Dialog; import com.vaadin.flow.component.dialog.DialogVariant; import com.vaadin.flow.component.grid.Grid; import com.vaadin.flow.component.html.Div; import com.vaadin.flow.router.Route; @Route("dialog-no-padding") public class DialogNoPadding extends Div { public DialogNoPadding() { Dialog dialog = new Dialog(); dialog.setHeaderTitle("Filter reports by users:"); dialog.add(createDialogContent(dialog)); dialog.getFooter().add(createFilterButton(dialog)); // tag::snippet[] dialog.addThemeVariants(DialogVariant.LUMO_NO_PADDING); // end::snippet[] Button button = new Button("Show dialog", e -> dialog.open()); add(dialog, button); } private static Grid<Person> createDialogContent(Dialog dialog) { Grid<Person> grid = new Grid<>(Person.class, false); grid.setItems(DataService.getPeople(50)); grid.setSelectionMode(Grid.SelectionMode.MULTI); grid.addColumn(Person::getFullName).setHeader("Name"); grid.getStyle().set("width", "500px").set("max-width", "100%"); return grid; } private static Button createFilterButton(Dialog dialog) { Button filterButton = new Button("Filter", e -> dialog.close()); filterButton.addThemeVariants(ButtonVariant.LUMO_PRIMARY); return filterButton; } }

dialog-no-padding.tsx

import React, { useEffect } from 'react'; import { useSignal } from '@vaadin/hilla-react-signals'; import { Button } from '@vaadin/react-components/Button.js'; import { Dialog } from '@vaadin/react-components/Dialog.js'; import { Grid } from '@vaadin/react-components/Grid.js'; import { GridColumn } from '@vaadin/react-components/GridColumn.js'; import { GridSelectionColumn } from '@vaadin/react-components/GridSelectionColumn.js'; import { getPeople } from 'Frontend/demo/domain/DataService'; import type Person from 'Frontend/generated/com/vaadin/demo/domain/Person'; function Example(): JSX.Element { const dialogOpened = useSignal(false); const people = useSignal<Person[]>([]); useEffect(() => { getPeople({ count: 50 }).then((result) => { people.value = result.people; }); }, []); return ( <> {/* tag::snippet[] */} <Dialog theme="no-padding" header-title="Filter reports by users:" opened={dialogOpened.value} onClosed={() => { dialogOpened.value = false; }} footer={ <Button theme="primary" onClick={() => { dialogOpened.value = false; }} > Filter </Button> } > <Grid items={people.value} style={{ width: '500px', maxWidth: '100%' }}> <GridSelectionColumn /> <GridColumn header="Name"> {({ item }) => ( <> {item.firstName} {item.lastName} </> )} </GridColumn> </Grid> </Dialog> {/* end::snippet[] */} <Button onClick={() => { dialogOpened.value = true; }} > Show dialog </Button> </> ); }

dialog-no-padding.ts

import '@vaadin/button'; import '@vaadin/dialog'; import '@vaadin/grid'; import '@vaadin/grid/vaadin-grid-selection-column.js'; import { html, LitElement } from 'lit'; import { customElement, state } from 'lit/decorators.js'; import { dialogFooterRenderer, dialogRenderer } from '@vaadin/dialog/lit.js'; import { columnBodyRenderer } from '@vaadin/grid/lit.js'; import { getPeople } from 'Frontend/demo/domain/DataService'; import type Person from 'Frontend/generated/com/vaadin/demo/domain/Person'; import { applyTheme } from 'Frontend/generated/theme'; @customElement('dialog-no-padding') export class Example extends LitElement { protected override createRenderRoot() { const root = super.createRenderRoot(); // Apply custom theme (only supported if your app uses one) applyTheme(root); return root; } @state() private dialogOpened = false; @state() private people: Person[] | undefined; protected override async firstUpdated() { const { people } = await getPeople({ count: 50 }); this.people = people; } protected override render() { return html` <!-- tag::snippet[] --> <vaadin-dialog theme="no-padding" header-title="Filter reports by users:" .opened="${this.dialogOpened}" @closed="${() => { this.dialogOpened = false; }}" ${dialogRenderer( () => html` <vaadin-grid .items="${this.people}" style="width: 500px; max-width: 100%;"> <vaadin-grid-selection-column></vaadin-grid-selection-column> <vaadin-grid-column header="Name" ${columnBodyRenderer<Person>( (item) => html`${item.firstName} ${item.lastName}`, [] )} ></vaadin-grid-column> </vaadin-grid> `, this.people )} ${dialogFooterRenderer( () => html` <vaadin-button theme="primary" @click="${this.close}">Filter</vaadin-button> `, [] )} ></vaadin-dialog> <!-- end::snippet[] --> <vaadin-button @click="${this.open}">Show dialog</vaadin-button> `; } private open() { this.dialogOpened = true; } private close() { this.dialogOpened = false; } }

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:

Important

Modal Parent Dialogs in Flow

See the 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.

Source code Java
Dialog dialog = new Dialog();
dialog.setModal(false);
Java HTML
<Dialog modeless>...</Dialog>
HTML HTML
<vaadin-dialog modeless>...</vaadin-dialog>
HTML

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

Note

In some use cases you may want to disable the server side modality. This can be done after Dialog has been opened. Source code Java
        Dialog dialog = new Dialog();
        dialog.addOpenedChangeListener(e -> {
            if (e.isOpened()) {
                UI.getCurrent().setChildComponentModal(dialog, false);
            }
        });
        // Dialog needs to be added to layout
        add(dialog);
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:

Source code Java
Dialog dialog = new Dialog();
dialog.setTop("50px");
dialog.setLeft("50px");
Java HTML
<Dialog top="50px" left="50px">...</Dialog>
HTML HTML
<vaadin-dialog top="50px" left="50px">...</vaadin-dialog>
HTML 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.

Open in a
new tab
Source code DialogDraggable.java

package com.vaadin.demo.component.dialog; import com.vaadin.flow.component.button.Button; import com.vaadin.flow.component.button.ButtonVariant; import com.vaadin.flow.component.dialog.Dialog; import com.vaadin.flow.component.html.Div; import com.vaadin.flow.component.html.H2; import com.vaadin.flow.component.orderedlayout.FlexComponent; import com.vaadin.flow.component.orderedlayout.VerticalLayout; import com.vaadin.flow.component.textfield.TextArea; import com.vaadin.flow.component.textfield.TextField; import com.vaadin.flow.router.Route; @Route("dialog-draggable") public class DialogDraggable extends Div { public DialogDraggable() { Dialog dialog = new Dialog(); dialog.getElement().setAttribute("aria-label", "Add note"); dialog.getHeader().add(createHeaderLayout()); createFooter(dialog); VerticalLayout dialogLayout = createDialogLayout(); dialog.add(dialogLayout); // tag::snippet1[] dialog.setModal(false); dialog.setDraggable(true); // end::snippet1[] Button button = new Button("Show dialog", e -> dialog.open()); add(dialog, button); } private static H2 createHeaderLayout() { H2 headline = new H2("Add note"); headline.addClassName("draggable"); headline.getStyle().set("margin", "0").set("font-size", "1.5em") .set("font-weight", "bold").set("cursor", "move") .set("padding", "var(--lumo-space-m) 0").set("flex", "1"); return headline; } private static VerticalLayout createDialogLayout() { TextField titleField = new TextField("Title"); TextArea descriptionArea = new TextArea("Description"); VerticalLayout fieldLayout = new VerticalLayout(titleField, descriptionArea); fieldLayout.setSpacing(false); fieldLayout.setPadding(false); fieldLayout.setAlignItems(FlexComponent.Alignment.STRETCH); fieldLayout.getStyle().set("width", "300px").set("max-width", "100%"); return fieldLayout; } private static void createFooter(Dialog dialog) { Button cancelButton = new Button("Cancel", e -> dialog.close()); Button saveButton = new Button("Add note", e -> dialog.close()); saveButton.addThemeVariants(ButtonVariant.LUMO_PRIMARY); dialog.getFooter().add(cancelButton); dialog.getFooter().add(saveButton); } }

dialog-draggable.tsx

import { useSignal } from '@vaadin/hilla-react-signals'; import { Button } from '@vaadin/react-components/Button.js'; import { Dialog } from '@vaadin/react-components/Dialog.js'; import { TextArea } from '@vaadin/react-components/TextArea.js'; import { TextField } from '@vaadin/react-components/TextField.js'; import { VerticalLayout } from '@vaadin/react-components/VerticalLayout.js'; function Example() { const dialogOpened = useSignal(false); const open = () => { dialogOpened.value = true; }; const close = () => { dialogOpened.value = false; }; return ( <> {/* tag::snippet[] */} <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(--lumo-space-m) 0', }} > Add note </h2> } footerRenderer={() => ( <> <Button onClick={close}>Cancel</Button> <Button theme="primary" onClick={close}> Add note </Button> </> )} > <VerticalLayout theme="spacing" style={{ width: '300px', maxWidth: '100%', alignItems: 'stretch' }} > <VerticalLayout style={{ alignItems: 'stretch' }}> <TextField label="Title" /> <TextArea label="Description" /> </VerticalLayout> </VerticalLayout> </Dialog> {/* end::snippet[] */} <Button onClick={open}>Show dialog</Button> </> ); }

dialog-draggable.ts

import '@vaadin/button'; import '@vaadin/dialog'; import '@vaadin/text-area'; import '@vaadin/text-field'; import '@vaadin/vertical-layout'; import { html, LitElement } from 'lit'; import { customElement, state } from 'lit/decorators.js'; import { dialogFooterRenderer, dialogHeaderRenderer, dialogRenderer } from '@vaadin/dialog/lit.js'; import { applyTheme } from 'Frontend/generated/theme'; @customElement('dialog-draggable') export class Example extends LitElement { protected override createRenderRoot() { const root = super.createRenderRoot(); // Apply custom theme (only supported if your app uses one) applyTheme(root); return root; } @state() private dialogOpened = false; protected override render() { return html` <!-- tag::snippet[] --> <vaadin-dialog aria-label="Add note" draggable modeless .opened="${this.dialogOpened}" @closed="${() => { this.dialogOpened = false; }}" ${dialogHeaderRenderer( () => html` <h2 class="draggable" style="flex: 1; cursor: move; margin: 0; font-size: 1.5em; font-weight: bold; padding: var(--lumo-space-m) 0;" > Add note </h2> `, [] )} ${dialogRenderer( () => html` <vaadin-vertical-layout theme="spacing" style="width: 300px; max-width: 100%; align-items: stretch;" > <vaadin-vertical-layout style="align-items: stretch;"> <vaadin-text-field label="Title"></vaadin-text-field> <vaadin-text-area label="Description"></vaadin-text-area> </vaadin-vertical-layout> </vaadin-vertical-layout> `, [] )} ${dialogFooterRenderer( () => html` <vaadin-button @click="${this.close}">Cancel</vaadin-button> <vaadin-button theme="primary" @click="${this.close}">Add note</vaadin-button> `, [] )} ></vaadin-dialog> <!-- end::snippet[] --> <vaadin-button @click="${this.open}">Show dialog</vaadin-button> `; } private open() { this.dialogOpened = true; } private close() { this.dialogOpened = false; } }

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.

Size

The Dialog size can be set with the width and height on the Dialog itself (since V24.6 for React and Lit). 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.

Source code Java
Dialog dialog = new Dialog();
dialog.setWidth("400px");
dialog.setHeight("200px");
Java HTML
<Dialog width="400px" height="200px">...</Dialog>
HTML HTML
<vaadin-dialog width="400px" height="200px">...</vaadin-dialog>
HTML 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.

Open in a
new tab
Source code DialogResizable.java

package com.vaadin.demo.component.dialog; import com.vaadin.demo.domain.DataService; import com.vaadin.demo.domain.Person; import com.vaadin.flow.component.button.Button; import com.vaadin.flow.component.dialog.Dialog; import com.vaadin.flow.component.grid.Grid; import com.vaadin.flow.component.html.Div; import com.vaadin.flow.component.orderedlayout.FlexComponent; import com.vaadin.flow.component.orderedlayout.VerticalLayout; import com.vaadin.flow.router.Route; import java.util.List; @Route("dialog-resizable") public class DialogResizable extends Div { public DialogResizable() { Dialog dialog = new Dialog(); dialog.setHeaderTitle("Employee list"); VerticalLayout dialogLayout = createDialogLayout(); dialog.add(dialogLayout); // tag::snippet[] dialog.setDraggable(true); dialog.setResizable(true); // end::snippet[] Button button = new Button("Show dialog", e -> dialog.open()); add(dialog, button); } private static VerticalLayout createDialogLayout() { Grid<Person> grid = new Grid<>(Person.class, false); grid.addColumn(Person::getFirstName).setHeader("First name"); grid.addColumn(Person::getLastName).setHeader("Last name"); grid.addColumn(Person::getEmail).setHeader("Email"); grid.addColumn(Person::getProfession).setHeader("Profession"); grid.addColumn(Person::getMembership).setHeader("Membership"); List<Person> people = DataService.getPeople(); grid.setItems(people); VerticalLayout dialogLayout = new VerticalLayout(grid); dialogLayout.setPadding(false); dialogLayout.setAlignItems(FlexComponent.Alignment.STRETCH); dialogLayout.getStyle().set("min-width", "300px") .set("max-width", "100%").set("height", "100%"); return dialogLayout; } }

dialog-resizable.tsx

import React, { useEffect } from 'react'; import { useSignal } from '@vaadin/hilla-react-signals'; import { Button } from '@vaadin/react-components/Button.js'; import { Dialog } from '@vaadin/react-components/Dialog.js'; import { Grid } from '@vaadin/react-components/Grid.js'; import { GridColumn } from '@vaadin/react-components/GridColumn.js'; import { VerticalLayout } from '@vaadin/react-components/VerticalLayout.js'; import { getPeople } from 'Frontend/demo/domain/DataService'; import type Person from 'Frontend/generated/com/vaadin/demo/domain/Person'; function Example() { const dialogOpened = useSignal(false); const people = useSignal<Person[]>([]); useEffect(() => { getPeople({ count: 50 }).then((result) => { people.value = result.people; }); }, []); function open() { dialogOpened.value = true; } return ( <> {/* tag::snippet[] */} <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> {/* end::snippet[] */} <Button onClick={open}>Show dialog</Button> </> ); }

dialog-resizable.ts

import '@vaadin/button'; import '@vaadin/dialog'; import '@vaadin/grid'; import '@vaadin/vertical-layout'; import { html, LitElement } from 'lit'; import { customElement, state } from 'lit/decorators.js'; import { dialogRenderer } from '@vaadin/dialog/lit.js'; import { getPeople } from 'Frontend/demo/domain/DataService'; import type Person from 'Frontend/generated/com/vaadin/demo/domain/Person'; import { applyTheme } from 'Frontend/generated/theme'; @customElement('dialog-resizable') export class Example extends LitElement { protected override createRenderRoot() { const root = super.createRenderRoot(); // Apply custom theme (only supported if your app uses one) applyTheme(root); return root; } @state() private dialogOpened = false; @state() private people: Person[] | undefined; protected override async firstUpdated() { const { people } = await getPeople({ count: 50 }); this.people = people; } protected override render() { return html` <!-- tag::snippet[] --> <vaadin-dialog header-title="Employee list" resizable draggable .opened="${this.dialogOpened}" @closed="${() => { this.dialogOpened = false; }}" ${dialogRenderer( () => html` <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> `, this.people )} ></vaadin-dialog> <!-- end::snippet[] --> <vaadin-button @click="${this.open}">Show dialog</vaadin-button> `; } private open() { this.dialogOpened = true; } }

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.

Open in a
new tab
Source code DialogClosing.java

package com.vaadin.demo.component.dialog; import com.vaadin.flow.component.button.Button; import com.vaadin.flow.component.dialog.Dialog; import com.vaadin.flow.component.html.Div; import com.vaadin.flow.component.html.H2; import com.vaadin.flow.component.html.Paragraph; import com.vaadin.flow.component.orderedlayout.FlexComponent; import com.vaadin.flow.component.orderedlayout.VerticalLayout; import com.vaadin.flow.router.Route; @Route("dialog-closing") public class DialogClosing extends Div { public DialogClosing() { Dialog dialog = new Dialog(); dialog.getElement().setAttribute("aria-label", "System maintenance hint"); VerticalLayout dialogLayout = createDialogLayout(dialog); dialog.add(dialogLayout); Button button = new Button("Show dialog", e -> dialog.open()); add(dialog, button); } private static VerticalLayout createDialogLayout(Dialog dialog) { H2 headline = new H2("System maintenance"); headline.getStyle().set("margin", "var(--lumo-space-m) 0") .set("font-size", "1.5em").set("font-weight", "bold"); Paragraph paragraph = new Paragraph( "System maintenance will begin at 3 PM. It is schedule to conclude at 5PM. We apologize for any inconvenience."); // tag::snippet[] Button closeButton = new Button("Close"); closeButton.addClickListener(e -> dialog.close()); // end::snippet[] VerticalLayout dialogLayout = new VerticalLayout(headline, paragraph, closeButton); dialogLayout.setPadding(false); dialogLayout.setAlignItems(FlexComponent.Alignment.STRETCH); dialogLayout.getStyle().set("width", "300px").set("max-width", "100%"); dialogLayout.setAlignSelf(FlexComponent.Alignment.END, closeButton); return dialogLayout; } }

dialog-closing.tsx

import { useSignal } from '@vaadin/hilla-react-signals'; import { Button } from '@vaadin/react-components/Button.js'; import { Dialog } from '@vaadin/react-components/Dialog.js'; import { VerticalLayout } from '@vaadin/react-components/VerticalLayout.js'; function Example() { const dialogOpened = useSignal(false); function open() { dialogOpened.value = true; } function close() { dialogOpened.value = false; } return ( <> {/* tag::snippet[] */} <Dialog aria-label="System maintenance notice" opened={dialogOpened.value} onClosed={() => { dialogOpened.value = false; }} > <VerticalLayout theme="spacing" style={{ width: '300px', maxWidth: '100%', alignItems: 'stretch' }} > <h2 style={{ margin: 'var(--lumo-space-m) 0', fontSize: '1.5em', fontWeight: 'bold' }}> System maintenance </h2> <p> System maintenance will begin at 3 PM. It is schedule to conclude at 5PM. We apologise for any inconvenience. </p> <Button onClick={close} style={{ alignSelf: 'flex-end' }}> Close </Button> </VerticalLayout> </Dialog> {/* end::snippet[] */} <Button onClick={open}>Show dialog</Button> </> ); }

dialog-closing.ts

import '@vaadin/button'; import '@vaadin/dialog'; import '@vaadin/vertical-layout'; import { html, LitElement } from 'lit'; import { customElement, state } from 'lit/decorators.js'; import { dialogRenderer } from '@vaadin/dialog/lit.js'; import { applyTheme } from 'Frontend/generated/theme'; @customElement('dialog-closing') export class Example extends LitElement { protected override createRenderRoot() { const root = super.createRenderRoot(); // Apply custom theme (only supported if your app uses one) applyTheme(root); return root; } @state() private dialogOpened = false; protected override render() { return html` <!-- tag::snippet[] --> <vaadin-dialog aria-label="System maintenance notice" .opened="${this.dialogOpened}" @closed="${() => { this.dialogOpened = false; }}" ${dialogRenderer( () => html` <vaadin-vertical-layout theme="spacing" style="width: 300px; max-width: 100%; align-items: stretch;" > <h2 style="margin: var(--lumo-space-m) 0; font-size: 1.5em; font-weight: bold;"> System maintenance </h2> <p> System maintenance will begin at 3 PM. It is schedule to conclude at 5PM. We apologise for any inconvenience. </p> <vaadin-button @click="${this.close}" style="align-self: flex-end;"> Close </vaadin-button> </vaadin-vertical-layout> `, [] )} ></vaadin-dialog> <!-- end::snippet[] --> <vaadin-button @click="${this.open}">Show dialog</vaadin-button> `; } private open() { this.dialogOpened = true; } private close() { this.dialogOpened = false; } }

Best Practices 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 when appropriate.

Component Usage recommendations

Confirm Dialog

Dialog for confirming user actions and decisions

Popover

A generic overlay whose position is anchored to an element in the UI.

Technical Multiple Dialogs and Server-side Modality in Flow

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

Due to the server-side modality mechanism in Flow, this means that closing a modal Dialog automatically also closes all its children, that is, any subsequent Dialogs opened after the modal.

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

Source code Java
Dialog d1 = new Dialog();
Dialog d2 = new Dialog();
add(d1, d2);  // Add dialogs to the UI before opening
d1.open();
d2.open();

EBCF8110-6074-4DAB-BE6B-662C813EDDC9

DetailsStylingDialogStyling

RetroSearch is an open source project built by @garambo | Open a GitHub Issue

Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo

HTML: 3.2 | Encoding: UTF-8 | Version: 0.7.4