Responsive Layouts
- Use Built-In Responsive Components First
- CSS Media Queries
- CSS Container Queries
- Lumo Utility Classes
- Best Practices
A responsive layout adapts to the size of the screen it’s shown on, presenting the right amount of information and interaction for each device. This guide covers how to implement a responsive Vaadin view. For the design decisions behind responsiveness — when to reduce features, go mobile-first, or build a separate mobile UI — see Responsiveness. For the layout components themselves — rows, columns, sizing, and alignment — see the Arrange with Layouts overview.
Responsiveness is a styling concern, handled with CSS rather than by detecting the screen size on the server. The core techniques — CSS media queries and container queries — work with any theme. The Lumo theme adds utility classes as a shortcut; with the Aura theme, which has no utility classes, you use the CSS techniques directly.
Use Built-In Responsive Components First
Many Vaadin components already adapt themselves, so check whether one fits before writing any responsive CSS. For example, App Layout collapses its drawer to a hamburger menu, Form Layout adjusts its column count, Dashboard reflows its widgets, and Menu Bar moves overflowing items into a sub-menu. For the full catalog of components with built-in responsive behavior, see Responsive Features in Vaadin.
CSS Media Queries
A media query applies a block of CSS only when the screen matches a condition, such as a maximum width. This is the primary tool for adapting to the viewport size.
Add a class name to the component from Java, then write the responsive rules in your view’s stylesheet:
Source code
Java
filterPanel.addClassName("filter-panel");Source code
CSS
.filter-panel {
display: flex;
}
/* Hide the panel on screens 640px wide or narrower */
@media (max-width: 640px) {
.filter-panel {
display: none;
}
}For how to attach a stylesheet and apply class names from Java, see Add Styling.
To keep behavior predictable, use a consistent set of breakpoints rather than targeting specific device widths. These match Vaadin’s Lumo utility classes (see below):
| Breakpoint | Min width | CSS prefix | Lumo Java constant |
|---|---|---|---|
(default) | 0px | (none) |
|
Small | 640px |
|
|
Medium | 768px |
|
|
Large | 1024px |
|
|
XLarge | 1280px |
|
|
XXLarge | 1536px |
|
|
Pattern: Responsive Card Grid
A common need is a grid of cards that shows more columns as the screen widens. CSS Grid handles this with a few media queries, and it works with any theme:
Source code
CSS
.card-grid {
display: grid;
gap: 1rem;
grid-template-columns: 1fr; /* one column on mobile */
}
@media (min-width: 640px) {
.card-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (min-width: 1024px) {
.card-grid { grid-template-columns: repeat(3, 1fr); }
}For a card grid that wraps automatically without media queries, see CSS Grid Layouts.
CSS Container Queries
A container query adapts a component to the width of its own container rather than the whole screen. Use it for resizable panels, dashboard widgets, and reusable components that may appear in different places — anywhere the component shouldn’t assume how much space it has.
Mark an element as a container, then query its width:
Source code
CSS
.side-panel {
container-type: inline-size;
container-name: side-panel;
}
/* Show the footer only when the panel itself is at least 400px wide */
.side-panel .footer {
display: none;
}
@container side-panel (min-width: 400px) {
.side-panel .footer {
display: flex;
}
}This makes a component self-contained: it adapts to the space it’s given, no matter where it’s placed.
Lumo Utility Classes
|
Note
| Utility classes require the Lumo theme. If you use Aura, use CSS media or container queries instead, as shown above. |
If you use Lumo, its utility classes are the fastest way to add responsive behavior without writing custom CSS. They follow a mobile-first pattern: the plain class sets the default (mobile) style, and a breakpoint-prefixed class overrides it on larger screens.
Load the utility classes with @StyleSheet imports on your application shell:
Source code
Java
@StyleSheet(Lumo.STYLESHEET)
@StyleSheet(Lumo.UTILITY_STYLESHEET)
public class Application implements AppShellConfigurator {
}|
Note
|
If you’re migrating from an older Vaadin version, note that loading utility classes through theme.json is no longer supported — use the @StyleSheet imports shown above.
|
Apply the classes from Java with addClassNames(). For example, to show a toolbar only on small screens:
Source code
Java
mobileToolbar.addClassNames(
LumoUtility.Display.FLEX, // visible by default (mobile)
LumoUtility.Display.Breakpoint.Medium.HIDDEN); // hidden at 768px and upOr to stack a container vertically on mobile and switch to a row on wider screens:
Source code
Java
container.addClassNames(
LumoUtility.Display.FLEX,
LumoUtility.FlexDirection.COLUMN, // stacked by default (mobile)
LumoUtility.FlexDirection.Breakpoint.Medium.ROW); // side by side at 768px and upFor the full list of utility classes and their breakpoint variants, see the Lumo Utility Classes reference.
Best Practices
-
Use CSS for responsiveness, not server-side detection. Avoid making layout decisions from
Page.retrieveExtendedClientDetails()or a browser-resize listener — CSS media and container queries are faster and need no server round-trip. -
Design mobile-first. Make the mobile layout the default and add complexity for larger screens. This matches how the Lumo breakpoints work.
-
Lean on the built-in responsive components — App Layout, Form Layout, Dashboard, and Menu Bar already adapt. Don’t rebuild what they provide.
-
Prefer container queries for reusable components. If a component might appear in containers of different widths, container queries make it self-adapting.
-
Design for fluid sizes, not specific devices. Users resize windows, split screens, and zoom. Test at many widths, not just "phone" and "desktop."
-
Check wrapping at in-between sizes. When you rely on
setWrap(true)or CSSflex-wrap, verify that items wrap gracefully between your breakpoints, not only at them.
|
Warning
| Don’t add a server-side browser-resize listener to switch layouts — it sends a request to the server on every resize. And avoid building separate mobile and desktop view classes unless the interaction patterns are genuinely different; one view with responsive CSS is far easier to maintain. |