Docs

Documentation versions (currently viewingVaadin 24)

App Layout

App Layout is a component for building common application layouts.

App Layout is a component for building common application layouts.

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.
Open in a
new tab
public class AppLayoutBasic extends AppLayout {

    public AppLayoutBasic() {
        DrawerToggle toggle = new DrawerToggle();

        H1 title = new H1("MyApp");
        title.getStyle().set("font-size", "var(--lumo-font-size-l)")
                .set("margin", "0");

        SideNav nav = getSideNav();

        Scroller scroller = new Scroller(nav);
        scroller.setClassName(LumoUtility.Padding.SMALL);

        addToDrawer(scroller);
        addToNavbar(toggle, title);
    }
}

The layout consists of three sections: a horizontal navigation bar (navbar), a collapsible navigation drawer (drawer) and a content area. An application’s main navigation blocks should be positioned in the navbar and/or drawer, whereas views are rendered in the content area.

App Layout is responsive and adjusts automatically to fit desktop, tablet, and mobile screen sizes.

The navbar can be located on top or to the side of the drawer.

When put on top, the navbar is typically used as an application header. Application headers contain, for example, the application’s name and branding, as well as actions that apply to the entire application, such as notifications, settings, etc.

Open in a
new tab
public class AppLayoutNavbarPlacement extends AppLayout {

    public AppLayoutNavbarPlacement() {
        DrawerToggle toggle = new DrawerToggle();

        H1 title = new H1("MyApp");
        title.getStyle().set("font-size", "var(--lumo-font-size-l)")
                .set("margin", "0");

        SideNav nav = getSideNav();

        Scroller scroller = new Scroller(nav);
        scroller.setClassName(LumoUtility.Padding.SMALL);

        addToDrawer(scroller);
        addToNavbar(toggle, title);
    }
}

When placed to the side, the navbar is often seen as a view header, housing the view’s title, and actions and secondary navigation that relate only to the current view.

Open in a
new tab
public class AppLayoutNavbarPlacementSide extends AppLayout {

    public AppLayoutNavbarPlacementSide() {
        DrawerToggle toggle = new DrawerToggle();

        H1 title = new H1("Dashboard");
        title.getStyle().set("font-size", "var(--lumo-font-size-l)")
                .set("margin", "0");

        SideNav nav = getSideNav();

        Scroller scroller = new Scroller(nav);
        scroller.setClassName(LumoUtility.Padding.SMALL);

        addToDrawer(scroller);
        addToNavbar(toggle, title);

        setPrimarySection(Section.DRAWER);
    }
}

Drawer Toggle

Show and hide the drawer using a Drawer Toggle (or a Button). The Drawer Toggle (☰) should always be accessible (unless the drawer is empty) and is most often situated in the navbar.

Scrolling Behavior

Depending on whether App Layout has a defined height, the way the content inside the layout scrolls can differ.

Auto Height

When the App Layout has an undefined/auto height, which is the default behavior, the <body> element is the scrolling container for the content inside the layout.

Open in a
new tab
public class AppLayoutHeightAuto extends AppLayout {

    public AppLayoutHeightAuto() {
        H1 title = new H1("MyApp");
        title.getStyle().set("font-size", "var(--lumo-font-size-l)")
                .set("margin", "var(--lumo-space-m)");
        addToNavbar(title);

        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");

        List<Person> people = DataService.getPeople(20);
        grid.setItems(people);
        grid.setAllRowsVisible(true);
        setContent(grid);
    }
}

The vertical scrollbar crosses the App Layout navbar and the content flows under it, allowing for translucent visual styles. Mobile browsers collapse and expand their toolbars when the user scrolls down and up, respectively. On iOS, you can tap the status bar (signal strength, battery, clock, etc.) to scroll back to the top of the page/view.

This behavior isn’t compatible with vertically scrollable Grids, or other scrolling containers within the content area whose height is 100%. To support those, define 100% height for the App Layout.

Full Height (100%)

To allow a nested component to take all the available vertical space inside the App Layout, you need to set an explicit height for the layout, commonly 100%. A common use case is to let a data grid fill the entire content area.

Note
Make sure all parent components/elements have 100% height
The full hierarchy of components from the App Layout to the <body> element need to have 100% height.
Open in a
new tab
public class AppLayoutHeightFull extends AppLayout {

    public AppLayoutHeightFull() {
        H1 title = new H1("MyApp");
        title.getStyle().set("font-size", "var(--lumo-font-size-l)")
                .set("margin", "var(--lumo-space-m)");
        addToNavbar(title);

        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");

        List<Person> people = DataService.getPeople();
        grid.setItems(people);
        setContent(grid);

        getElement().getStyle().set("height", "100%");
        grid.setHeight("100%");
        grid.addThemeVariants(GridVariant.LUMO_NO_BORDER);
    }
}

The vertical scrollbar stays within the layout content area, and mobile browsers don’t collapse their toolbars when the content area is scrolled down.

Bottom Navbar on Small Touchscreens

When the navbar is used for navigation, the touch-optimized navbar slot can be used to provide a separate version of the navigation at the bottom of the UI, optimized for mobile phones.

Open in a
new tab
public class AppLayoutBottomNavbar extends AppLayout {

    public AppLayoutBottomNavbar() {
        H1 title = new H1("MyApp");
        title.getStyle().set("font-size", "var(--lumo-font-size-l)")
                .set("margin", "var(--lumo-space-m) var(--lumo-space-l)");

        HorizontalLayout nav = getNavigation();

        H2 viewTitle = new H2("View title");
        Paragraph viewContent = new Paragraph("View content");

        Div content = new Div();
        content.add(viewTitle, viewContent);

        addToNavbar(title);
        addToNavbar(true, nav);

        setContent(content);
    }
}

Best Practices

Make the choice between navbar and drawer based primarily on the number of items placed in it.

The navbar is a good choice for a small number of items (3–5), as these can fit into the viewport without scrolling.

Open in a
new tab
public class AppLayoutNavbar extends AppLayout {

    public AppLayoutNavbar() {
        H1 title = new H1("MyApp");
        title.getStyle().set("font-size", "var(--lumo-font-size-l)")
                .set("left", "var(--lumo-space-l)").set("margin", "0")
                .set("position", "absolute");

        HorizontalLayout navigation = getNavigation();
        navigation.getElement()

        addToNavbar(title, navigation);
    }
}

When more items need to be displayed, or if small-screen support is a priority, the drawer is a better choice, as it can accommodate a longer list of links without scrolling, and collapses into a hamburger menu on small screens. Furthermore, a vertical list of items is easier for the user to scan.

Open in a
new tab
public class AppLayoutDrawer extends AppLayout {

    public AppLayoutDrawer() {
        DrawerToggle toggle = new DrawerToggle();

        H1 title = new H1("Dashboard");
        title.getStyle().set("font-size", "var(--lumo-font-size-l)")
                .set("margin", "0");

        SideNav nav = getTabs();

        Scroller scroller = new Scroller(nav);
        scroller.setClassName(LumoUtility.Padding.SMALL);

        addToDrawer(scroller);
        addToNavbar(toggle, title);

        setPrimarySection(Section.DRAWER);
    }
}

For applications that require multilevel or hierarchical navigation, use the drawer to (at least) house the first level. The secondary (and tertiary) navigation items can be placed in either the drawer or the navbar.

Open in a
new tab
public class AppLayoutSecondaryNavigation extends AppLayout {

    public AppLayoutSecondaryNavigation() {
        H1 appTitle = new H1("MyApp");
        appTitle.getStyle().set("font-size", "var(--lumo-font-size-l)")
                .set("line-height", "var(--lumo-size-l)")
                .set("margin", "0 var(--lumo-space-m)");

        SideNav views = getPrimaryNavigation();

        Scroller scroller = new Scroller(views);
        scroller.setClassName(LumoUtility.Padding.SMALL);

        DrawerToggle toggle = new DrawerToggle();

        H2 viewTitle = new H2("Orders");
        viewTitle.getStyle().set("font-size", "var(--lumo-font-size-l)")
                .set("margin", "0");

        HorizontalLayout subViews = getSecondaryNavigation();

        HorizontalLayout wrapper = new HorizontalLayout(toggle, viewTitle);
        wrapper.setAlignItems(FlexComponent.Alignment.CENTER);
        wrapper.setSpacing(false);

        VerticalLayout viewHeader = new VerticalLayout(wrapper, subViews);
        viewHeader.setPadding(false);
        viewHeader.setSpacing(false);

        addToDrawer(appTitle, scroller);
        addToNavbar(viewHeader);

        setPrimarySection(Section.DRAWER);
    }
}

3005EA19-8E28-4BF2-8A0A-FC3F46C04F1B