Java responsive web app layout: side navigation in webforJ

The quickest way to build a responsive Java web app layout in webforJ is AppLayout for the shell, AppNav for the side navigation, and ColumnsLayout or FlexLayout for the content. AppLayout gives you a fixed header and footer plus a drawer that turns into a popover on narrow screens. Everything is plain Java and every view is a route.
This guide builds the whole shell in one pass: the drawer and its breakpoint, navigation linked to routes, a content grid that changes column count with the viewport, and what happens on a phone.
Need a component that isn't covered here?
Ask the team what fits your screen.
Which layout component does what
Each component covers one job, and they nest inside each other.
| Component | Job | Responsive behavior |
|---|---|---|
AppLayout | App shell with header, drawer, footer and content area | Drawer becomes a popover at a configurable breakpoint |
AppNav | Hierarchical side navigation | Lives in the drawer, so it follows the drawer |
ColumnsLayout | Multi-column forms | Column count changes at breakpoints you define |
FlexLayout | Row or column of items | Items can wrap when they no longer fit |
Build the app shell with AppLayout
AppLayout is a ready-made page structure. The header and footer are fixed, the drawer slides in and out, and the content area scrolls. Each part is a Div that can hold any webforJ component. It works with webforJ dark mode, and the AppLayout docs list every option.
Make the shell a route. Views then render inside it through the outlet parameter of @Route, so the header and drawer persist while the content changes. This pattern is a layout route.
@AppMeta(name = "viewport",
content = "width=device-width, initial-scale=1.0, viewport-fit=cover")
@Route
public class Shell extends Composite<AppLayout> {
public Shell() {
AppLayout layout = getBoundComponent();
layout.setDrawerBreakpoint("(max-width: 700px)");
layout.setHeaderOffscreen(false);
layout.addToDrawerTitle(new Div("Acme"));
layout.addToHeader(new AppDrawerToggle(), new H1("Orders"));
layout.addToFooter(new Div("Acme Orders"));
AppNav nav = new AppNav();
nav.add(new AppNavLabel("Sales"));
nav.addItem(new AppNavItem("Inbox", InboxView.class, TablerIcon.create("inbox")));
nav.addItem(new AppNavItem("Outbox", OutboxView.class, TablerIcon.create("send-2")));
layout.addToDrawer(nav);
}
}
Three details matter here:
- The
viewportmeta tag withviewport-fit=coverscales the page to fill the device display. - By default the header and footer sit beside an open drawer.
setHeaderOffscreen(false)makes the header take the full width and pushes the drawer below it.setFooterOffscreen(false)does the same for the footer. AppDrawerToggleis a hamburger button. It works without an event listener.
Set the drawer breakpoint
On a wide screen the drawer stays open next to the content. At 800px or narrower the drawer switches to popover mode by default, which means it slides over the content with an overlay. That switch point is the drawer breakpoint.
setDrawerBreakpoint() takes any valid CSS media query. The shell in the previous section uses (max-width: 700px), so mid-size screens keep the docked drawer and phones get the popover.
AppLayout also supports three drawer positions: DrawerPlacement.LEFT, DrawerPlacement.RIGHT and DrawerPlacement.HIDDEN. Use HIDDEN for pages that need the full width and no navigation.
