From vaadin-claude
Guides building responsive layouts in Vaadin 25 using CSS media/container queries and built-in responsive components. Activates for layout, mobile support, breakpoints, and responsive design queries.
npx claudepluginhub vaadin/claude-plugin --plugin vaadin-claudeThis skill uses the workspace's default tool permissions.
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"`.
Mandates invoking relevant skills via tools before any response in coding sessions. Covers access, priorities, and adaptations for Claude Code, Copilot CLI, Gemini CLI.
Share bugs, ideas, or general feedback.
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 cardGrid
Use 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.