Docs

Documentation versions (currently viewingVaadin 24)

Master-Detail Layout

Master-Detail Layout makes it easy to create responsive horizontally or vertically split UIs.

Master-Detail Layout is component for building UIs with a horizontally or vertically split pair of a master (or primary) area and a detail (or secondary) area that can responsively switch to an overlay.

Note
Preview Feature

This is a preview version of Master-Detail Layout. You need to enable it with the feature flag com.vaadin.experimental.masterDetailLayoutComponent. Preview versions may lack some planned features, and breaking changes may be introduced in any Vaadin version. We encourage you to try it out and provide feedback to help us improve it.

Important
Scaled down examples
The examples on this page are scaled down so that their viewport-size-dependent behavior can be demonstrated. Some examples also change their behavior based on your browser viewport size.

In the example below, clicking a row in the table reveals the detail area which is rendered next to the master area by default. Drag the splitter to change the width of the layout: the detail area will switch to an overlay when the master area’s minimum width is reached.

Open in a
new tab
link:include::../../../frontend/demo/component/master-detail-layout/react/master-detail-layout-basic.tsx[]
MasterDetailLayout layout = new MasterDetailLayout();
layout.setMasterMinSize("600px");
layout.setDetailSize("300px");

PersonList personList = new PersonList(DataService.getPeople());
layout.setMaster(personList);

PersonDetail personDetail = new PersonDetail();

personList.getGrid().asSingleSelect().addValueChangeListener(event -> {
    Person selectedPerson = event.getValue();
    if (selectedPerson != null) {
        personDetail.setPerson(selectedPerson);
        layout.setDetail(personDetail);
    } else {
        layout.setDetail(null);
    }
});

personDetail.addCloseListener(event -> personList.getGrid().deselectAll());

Orientation

By default, the Master-Detail Layout is split horizontally. This can be changed to a vertical split.

Open in a
new tab
import React, { useEffect } from 'react';
import { useSignal } from '@vaadin/hilla-react-signals';
import { MasterDetailLayout, SplitLayout } from '@vaadin/react-components';
import PersonDetail from 'Frontend/demo/component/master-detail-layout/react/PersonDetail';
import PersonList from 'Frontend/demo/component/master-detail-layout/react/PersonList';
import { getPeople } from 'Frontend/demo/domain/DataService';
import type Person from 'Frontend/generated/com/vaadin/demo/domain/Person';

function Example() {
  const items = useSignal<Person[]>([]);
  const selectedPerson = useSignal<Person | null>(null);
  useEffect(() => {
    getPeople().then(({ people }) => {
      items.value = people;
    });
  }, []);

  return (
    <SplitLayout orientation="vertical" style={{ height: '100%' }}>
      <MasterDetailLayout
        orientation="vertical"
        masterMinSize="150px"
        detailSize="250px"
      >
        <MasterDetailLayout.Master>
          <PersonList
            people={items.value}
            selectedPerson={selectedPerson.value}
            onSelect={(person) => {
              selectedPerson.value = person;
            }}
          />
        </MasterDetailLayout.Master>
        <MasterDetailLayout.Detail>
          {selectedPerson.value ? (
            <PersonDetail
              person={selectedPerson.value}
              onClose={() => {
                selectedPerson.value = null;
              }}
            />
          ) : null}
        </MasterDetailLayout.Detail>
      </MasterDetailLayout>
      <div style={{ flex: '0 0 auto', backgroundColor: 'var(--lumo-contrast-5pct)', textAlign: 'center' }}>
        <span style={{fontWeight: 'bold', minHeight: '1.75em'}}>Drag to resize</span>
      </div>
    </SplitLayout>
  );
}
MasterDetailLayout layout = new MasterDetailLayout();
layout.setOrientation(MasterDetailLayout.Orientation.VERTICAL);

Responsive Details Area

The detail area can be rendered in three different ways:

  • Split: Side-by-side with the master area (horizontally or vertically, depending on the orientation);

  • Drawer: As an overlay partially covering the master area;

  • Stack: As a full-size overlay fully covering the master area.

Overlay Based on Available Space

For each area, either a fixed size or a minimum size can be specified. The area with a minimum size takes whatever space is available next to the fixed size area. If the available space is smaller than the minimum size, the detail area is rendered as an overlay.

The two most common configurations are:

  • A flexible master area with a minimum size, next to a fixed-size detail area;

  • A fixed-size master area, next to a flexible detail area with a minimum size.

If both areas are configured to be flexible, whichever reaches its minimum size first determines the overlay breakpoint.

If not explicitly set, the layout tries to determine an appropriate minimum size automatically based on the content.

layout.setMasterMinSize("600px");
layout.setDetailSize("300px");

Stack Mode

The layout can be configured to make the detail area in the overlay mode render as a stack (i.e. fully cover the master area):

layout.setOverlayMode(MasterDetailLayout.OverlayMode.STACK);

Forced Overlay Mode

The layout can be configured to always render the detail area as an overlay (either as drawer or stack), regardless of minimum sizes:

layout.setForceOverlay(true);

Overlay Containment Modes

The overlay can be configured to render in two different ways, called containment modes:

  • Layout: The overlay only covers the master area (default);

  • Viewport: The overlay covers the entire viewport (i.e. page).

layout.setContainment(MasterDetailLayout.Containment.VIEWPORT);

Router Integration

Master-Detail Layout can be used as a router layout (see Flow/Hilla), so that nested views are automatically rendered in the details area of the component. This allows showing nested views without having to manage the contents of the details area manually when the route changes, while providing the same benefits such as responsive behavior that the component normally provides.

The Flow MasterDetailLayout component implements the RouterLayout interface. When using a view class that extends from MasterDetailLayout as a layout for a nested view, that view is then automatically shown in the details area of the component.

The example below shows how to set up a master and a detail view. The master view is ProductListView, which would show a list of products, and the detail view is ProductDetailView, which shows information about a specific product. The ProductListView extends from MasterDetailLayout, so that it can be used as a route layout by the detail view. It also configures a @Route so that it can be navigated to by itself. Assuming there is a main layout for the application, for example one using AppLayout, it configures that as a parent layout. The ProductDetailView configures a @Route, using the ProductListView as the route layout.

With this setup, when navigating to /products, the layout would only show the product list. When navigating to a product detail, for example /products/1, it would then also show the product details next to, or on top of, the product list.

@ParentLayout(MainLayout.class)
@Route(value = "products", layout = MainLayout.class)
public class ProductListView extends MasterDetailLayout { ... }

@Route(value = "products/:productId", layout = ProductListView.class)
public class ProductDetailView extends VerticalLayout { ... }
Component Usage Recommendation

Split Layout

A component with two content areas and a draggable resize handle between them.