Guide Claude on building responsive Vaadin 25 layouts that adapt to different screen sizes. This skill should be used when the user asks to "make a layout responsive", "support mobile", "adapt to screen size", "use breakpoints", "use media queries", "use container queries", "responsive design", "mobile first", or needs help making a Vaadin Flow view work well on both desktop and mobile devices.
68
83%
Does it follow best practices?
Impact
—
No eval scenarios have been run
Passed
No known issues
Use the Vaadin MCP tools (search_vaadin_docs, get_component_java_api) to look up the latest documentation whenever uncertain about a specific API detail. Always set vaadin_version to "25" and ui_language to "java".
Responsiveness in Vaadin means adapting the UI to best use available screen space — not just squeezing or stretching elements. The goal is to present the right amount of information and interaction for each viewport size.
Three strategies, in order of increasing effort:
Start with strategy 2 unless you have a strong reason not to.
Leverage these before writing custom responsive logic — they handle adaptation automatically:
The primary tool for viewport-based responsiveness. Define styles that activate at specific viewport widths.
/* In your view's CSS file */
.filter-panel {
display: flex;
}
@media (max-width: 640px) {
.filter-panel {
display: none;
}
}Apply CSS class names from Java and let the CSS handle the responsive logic. This keeps responsive behavior in CSS where it belongs, rather than trying to detect screen sizes server-side.
When responsiveness should be based on a component's container width rather than the viewport. Useful for resizable panels, reusable components that appear in different contexts, and dashboard widgets.
.sidepanel {
container-type: inline-size;
container-name: sidepanel;
}
.sidepanel .footer {
display: none;
}
@container sidepanel (min-width: 400px) {
.footer {
display: flex;
}
}Container queries make components self-contained — they adapt to their own available space rather than assuming a specific viewport size.
Vaadin's Lumo utility classes provide a mobile-first responsive system similar to Tailwind CSS. They are the fastest way to add responsive behavior without writing custom CSS.
Note: These utility classes only work with the Lumo theme. If using Aura, use CSS media queries or container queries instead (see sections above).
Setup (required in Vaadin 25):
@StyleSheet(Lumo.STYLESHEET)
@StyleSheet(Lumo.UTILITY_STYLESHEET)
@StyleSheet("styles.css")
public class Application implements AppShellConfigurator {
}Note: Loading Lumo Utility Classes through theme.json is no longer supported in Vaadin 25. Use @StyleSheet imports instead.
Breakpoints (mobile-first):
| Breakpoint | Min width | Java constant prefix |
|---|---|---|
| (default) | 0px | LumoUtility.Display.FLEX etc. |
| Small | 640px | Display.Breakpoint.Small.* |
| Medium | 768px | Display.Breakpoint.Medium.* |
| Large | 1024px | Display.Breakpoint.Large.* |
| XLarge | 1280px | Display.Breakpoint.XLarge.* |
| XXLarge | 1536px | Display.Breakpoint.XXLarge.* |
Example — show a mobile toolbar only on small screens:
mobileToolbar.addClassNames(
LumoUtility.Display.FLEX, // visible by default (mobile)
LumoUtility.Display.Breakpoint.Small.HIDDEN // hidden at 640px+
);Example — switch from vertical to horizontal layout at a breakpoint:
container.addClassNames(
LumoUtility.Display.FLEX,
LumoUtility.FlexDirection.COLUMN, // stack vertically (mobile)
LumoUtility.FlexDirection.Breakpoint.Medium.ROW // row at 768px+
);The utility classes follow a mobile-first pattern: define the mobile style as the default, then override at larger breakpoints. This matches the CSS convention and produces cleaner code.
On desktop, show a filter sidebar. On mobile, hide it behind a toggle button.
// Lumo theme only — uses LumoUtility classes
// Filter panel — hidden on mobile, shown on desktop
VerticalLayout filterPanel = new VerticalLayout();
filterPanel.addClassNames(
LumoUtility.Display.HIDDEN, // hidden by default
LumoUtility.Display.Breakpoint.Medium.FLEX // shown at 768px+
);
// Toggle button — shown on mobile, hidden on desktop
Button filterToggle = new Button("Filters");
filterToggle.addClassNames(
LumoUtility.Display.INLINE_FLEX, // shown by default
LumoUtility.Display.Breakpoint.Medium.HIDDEN // hidden at 768px+
);Use CSS Grid for a card layout that adapts its column count.
.card-grid {
display: grid;
gap: 1rem; /* or use theme token: var(--lumo-space-m) for Lumo */
grid-template-columns: 1fr; /* 1 column on mobile */
}
@media (min-width: 640px) {
.card-grid {
grid-template-columns: repeat(2, 1fr); /* 2 columns */
}
}
@media (min-width: 1024px) {
.card-grid {
grid-template-columns: repeat(3, 1fr); /* 3 columns */
}
}Div cardGrid = new Div();
cardGrid.addClassName("card-grid");
// Add Card components to cardGridUse AppLayout with drawer placement. On small viewports, AppLayout automatically converts the drawer to an overlay. For full customization, combine with media queries to move navigation to a bottom bar.
Page.retrieveExtendedClientDetails() or UI.getCurrent().getPage().addBrowserWindowResizeListener() for layout decisions. CSS media/container queries are more performant and don't require a server round-trip.setWrap(true) on HorizontalLayout or flex-wrap in CSS, verify that items wrap gracefully at intermediate sizes, not just at your target breakpoints.For the complete list of Lumo utility class breakpoints and responsive constants, see references/responsive-patterns.md.
e47fdfe
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.