Docs

Documentation versions (currently viewingVaadin 25.4 (pre-release))

Dialogs & Drawers

Learn how to show forms in dialogs and drawers.

In business applications, dialogs are typically used for creating new items, while drawers are more often used for editing existing ones. Drawers are often tied to a selection. Selecting an item typically opens a drawer, closing the drawer then clears the selection.

Tip
Part of a Series
This is part 4 of the Add a Form series. It builds on the concepts introduced in the Fields & Binding, Form Validation and Loading & Saving guides.

By implementing the form as a standalone component, you can reuse it in both dialogs and drawers.

Displaying Forms in Dialogs

When working with dialogs in Vaadin, it’s important to remember they do not alter the application’s control flow. For example, in Swing, you can pass control to a dialog and wait until it closes. After that, control returns to the calling code and you can proceed, depending on what option the user selected. In Vaadin, opening a dialog is another way of displaying a UI element — it doesn’t block execution or pause logic. Instead, user interactions are handled through event listeners or callbacks.

The following example shows a dialog used to create new project proposals. The caller supplies an onSaveCallback, which is triggered when the user clicks the Create Proposal button:

Source code
Java
public class ProposalDialog extends Dialog {

    private final SerializableConsumer<Proposal> onSaveCallback;
    private final ProposalForm form;

    public ProposalDialog(SerializableConsumer<Proposal> onSaveCallback) {
        this.onSaveCallback = onSaveCallback;

        // Create the components
        form = new ProposalForm();

        var saveBtn = new Button("Create Proposal", event -> save());
        saveBtn.addThemeVariants(ButtonVariant.PRIMARY);

        var cancelBtn = new Button("Cancel", event -> close());

        // Configure the dialog
        setHeaderTitle("New Proposal");
        add(form);
        getFooter().add(cancelBtn, saveBtn);
    }

    private void save() {
        form.getFormDataObject().ifPresent(proposal -> { 1
            onSaveCallback.accept(proposal); 2
            close();
        });
    }
}
  1. Writes the form data to a new Proposal FDO (Form Data Object).

  2. Uses a callback to let the caller decide how to save the FDO.

Here’s how you might use the dialog in your application:

Source code
Java
var grid = new Grid<Proposal>();
// Configure grid here...

var createProposalButton = new Button("Create Proposal", event -> {
    new ProposalDialog(proposal -> {
        var saved = proposalService.save(proposal); 1
        grid.getDataProvider().refreshAll(); 2
        grid.select(saved); 3
    }).open();
});
  1. Saves the proposal with an application service.

  2. Refreshes the grid of proposals so that the new one shows up.

  3. Selects the newly added proposal, opening the edit drawer.

Displaying Forms in Drawers

A drawer shows the form next to the items the user selects from, or on top of them when there isn’t enough room. Use the Master-Detail Layout component for this. It shows the drawer in its detail area, and switches it to an overlay on narrow screens. For more about the component and the master-detail pattern, see the Add a Master-Detail View guide.

The following example shows a drawer that reuses the same form component from the dialog example to edit project proposals. The caller provides two callbacks: an onSaveCallback for handling save logic, and an onCloseCallback that runs when the user closes the drawer:

Source code
Java
public class ProposalDrawer extends Section {

    private final SerializableFunction<Proposal, Proposal> onSaveCallback;
    private final SerializableRunnable onCloseCallback;
    private final ProposalForm form;

    public ProposalDrawer(SerializableFunction<Proposal, Proposal> onSaveCallback,
                          SerializableRunnable onCloseCallback) {
        this.onSaveCallback = onSaveCallback;
        this.onCloseCallback = onCloseCallback;

        // Create the components
        form = new ProposalForm();

        var header = new H2("Edit Proposal");
        header.setId("proposal-drawer-header"); 1
        setAriaLabelledBy("proposal-drawer-header");

        var saveBtn = new Button("Save", event -> save());
        saveBtn.addThemeVariants(ButtonVariant.PRIMARY);

        var closeBtn = new Button("Close", event -> close());

        var buttons = new HorizontalLayout(closeBtn, saveBtn);

        // Configure the drawer
        add(header, form, buttons);
    }

    public void setProposal(Proposal proposal) {
        form.setFormDataObject(proposal);
    }

    private void save() {
        form.getFormDataObject().ifPresent(proposal -> {
            var savedProposal = onSaveCallback.apply(proposal);
            form.setFormDataObject(savedProposal);
        });
    }

    private void close() {
        onCloseCallback.run();
    }
}
  1. Example accessibility improvements — recommended, but not required for drawer functionality.

The drawer doesn’t show or hide itself. Instead, the view extends MasterDetailLayout, and sets the drawer as the detail whenever the user selects a proposal in the grid:

Source code
Java
@Route("proposals")
public class ProposalView extends MasterDetailLayout {

    public ProposalView(ProposalService proposalService) {
        var grid = new Grid<Proposal>();
        // Configure the grid here...

        var drawer = new ProposalDrawer(
            proposal -> {
                var savedProposal = proposalService.save(proposal); 1
                grid.getDataProvider().refreshAll(); 2
                return savedProposal;
            },
            grid::deselectAll 3
        );
        grid.addSelectionListener(event -> {
            var selected = event.getFirstSelectedItem();
            selected.ifPresent(drawer::setProposal);
            setDetail(selected.isPresent() ? drawer : null); 4
        });
        addBackdropClickListener(event -> grid.deselectAll()); 5
        addDetailEscapePressListener(event -> grid.deselectAll());

        setMaster(grid);
        setSizeFull();
    }
}
  1. Saves the proposal with an application service.

  2. Refreshes the grid so that the updated proposal shows up.

  3. Clears the grid selection when the user closes the drawer.

  4. Shows the selected proposal in the drawer, or closes the drawer if the selection is empty.

  5. Clears the selection, and thereby closes the drawer, when the user clicks outside the drawer or presses Esc while it’s shown as an overlay.