diff --git a/articles/styling/_images/align_items_large.png b/articles/styling/_images/align_items_large.png new file mode 100644 index 0000000000..37fcd0341a Binary files /dev/null and b/articles/styling/_images/align_items_large.png differ diff --git a/articles/styling/_images/align_items_medium.png b/articles/styling/_images/align_items_medium.png new file mode 100644 index 0000000000..5d21a69c46 Binary files /dev/null and b/articles/styling/_images/align_items_medium.png differ diff --git a/articles/styling/_images/align_items_small.png b/articles/styling/_images/align_items_small.png new file mode 100644 index 0000000000..093f9229de Binary files /dev/null and b/articles/styling/_images/align_items_small.png differ diff --git a/articles/styling/_images/display_desktop.png b/articles/styling/_images/display_desktop.png new file mode 100644 index 0000000000..81850159f8 Binary files /dev/null and b/articles/styling/_images/display_desktop.png differ diff --git a/articles/styling/_images/display_mobile.png b/articles/styling/_images/display_mobile.png new file mode 100644 index 0000000000..ff9affe16a Binary files /dev/null and b/articles/styling/_images/display_mobile.png differ diff --git a/articles/styling/_images/display_tablet.png b/articles/styling/_images/display_tablet.png new file mode 100644 index 0000000000..193ddbde67 Binary files /dev/null and b/articles/styling/_images/display_tablet.png differ diff --git a/articles/styling/_images/flex_direction_column.png b/articles/styling/_images/flex_direction_column.png new file mode 100644 index 0000000000..848c07b97f Binary files /dev/null and b/articles/styling/_images/flex_direction_column.png differ diff --git a/articles/styling/_images/flex_direction_row.png b/articles/styling/_images/flex_direction_row.png new file mode 100644 index 0000000000..66f88ed30d Binary files /dev/null and b/articles/styling/_images/flex_direction_row.png differ diff --git a/articles/styling/_images/font_size_large.png b/articles/styling/_images/font_size_large.png new file mode 100644 index 0000000000..84fe81b30f Binary files /dev/null and b/articles/styling/_images/font_size_large.png differ diff --git a/articles/styling/_images/font_size_medium.png b/articles/styling/_images/font_size_medium.png new file mode 100644 index 0000000000..4055eb66dc Binary files /dev/null and b/articles/styling/_images/font_size_medium.png differ diff --git a/articles/styling/_images/font_size_small.png b/articles/styling/_images/font_size_small.png new file mode 100644 index 0000000000..ca091936ff Binary files /dev/null and b/articles/styling/_images/font_size_small.png differ diff --git a/articles/styling/_images/grid_extra_large.png b/articles/styling/_images/grid_extra_large.png new file mode 100644 index 0000000000..c92c64b131 Binary files /dev/null and b/articles/styling/_images/grid_extra_large.png differ diff --git a/articles/styling/_images/grid_medium.png b/articles/styling/_images/grid_medium.png new file mode 100644 index 0000000000..d5c7f04bfd Binary files /dev/null and b/articles/styling/_images/grid_medium.png differ diff --git a/articles/styling/_images/grid_small.png b/articles/styling/_images/grid_small.png new file mode 100644 index 0000000000..6b47293829 Binary files /dev/null and b/articles/styling/_images/grid_small.png differ diff --git a/articles/styling/_images/position_large.png b/articles/styling/_images/position_large.png new file mode 100644 index 0000000000..9c3e9b81bb Binary files /dev/null and b/articles/styling/_images/position_large.png differ diff --git a/articles/styling/_images/position_medium.png b/articles/styling/_images/position_medium.png new file mode 100644 index 0000000000..4932c6b280 Binary files /dev/null and b/articles/styling/_images/position_medium.png differ diff --git a/articles/styling/_images/position_small.png b/articles/styling/_images/position_small.png new file mode 100644 index 0000000000..9b89449497 Binary files /dev/null and b/articles/styling/_images/position_small.png differ diff --git a/articles/styling/themes/lumo/lumo-breakpoint.adoc b/articles/styling/themes/lumo/lumo-breakpoint.adoc new file mode 100644 index 0000000000..0edf1d24a7 --- /dev/null +++ b/articles/styling/themes/lumo/lumo-breakpoint.adoc @@ -0,0 +1,1072 @@ +--- +title: Responsive Utility Classes +page-title: How to use Lumo's responsive utility classes in Vaadin +description: Applying styles based on screen size using Lumo's responsive breakpoint utility classes in Vaadin. +meta-description: Learn how to create responsive layouts in Vaadin Flow with Lumo's breakpoint-based utility classes for display, flex direction, font size, grid, and position. +order: 40 +--- + += Lumo Utility Classes: Responsive Breakpoints + +Lumo includes a powerful set of responsive utility classes that allow you to apply specific styles based on the screen (viewport) size. +These classes use breakpoint CSS class name prefixes (`sm:`, `md:`, `lg:`, `xl:`, and `2xl:`) to apply styles only when the screen width meets a certain minimum threshold. + +You can apply these classes to any Flow component using the `addClassNames()` method. +This enables you to build complex, adaptive interfaces declaratively and directly from your Java code. + +[IMPORTANT] +.Exclusive Focus on Breakpoints +==== +This document focuses specifically on the **responsive breakpoint prefixes** (e.g., `sm:`, `md:`) and their corresponding Java APIs in the nested `Breakpoint` classes, such as `LumoUtility.Display.Breakpoint`. + +Although the examples use various base utility classes (like `Display.FLEX` or `Padding.MEDIUM`) to provide context, they are not the main topic here. +For a complete reference of all available utility classes, see the main <> documentation. +==== + +The default breakpoints are activated at the following minimum widths: + +.Available Responsive Breakpoint Classes +|=== +|Breakpoint |CSS class name prefixes |Minimum width |Equivalent screens |Equivalent in CSS + +|`Breakpoint.Small` +|`sm` +|`640px` +|Mobile devices +|`@media (min-width: 640px) {}` + +|`Breakpoint.Medium` +|`md` +|`768px` +|Tablets +|`@media (min-width: 768px) {}` + +|`Breakpoint.Large` +|`lg` +|`1024px` +|Small laptops +|`@media (min-width: 1024px) {}` + +|`Breakpoint.XLarge` +|`xl` +|`1280px` +|Large laptops +|`@media (min-width: 1280px) {}` + +|`Breakpoint.XXLarge` +|`2xl` +|`1536px` +|Large desktops +|`@media (min-width: 1536px) {}` +|=== + +== Responsive Utilities and Limitations + +Currently, Lumo provides responsive breakpoint prefixes (e.g., `sm:`, `md:`) for a specific set of utility groups. +This allows you to apply styles that adapt to different screen sizes directly from Java. + +The utility groups that support responsive breakpoints are: + +1. *Align Items:* Controls alignment of flex items along the cross-axis. (e.g., `sm:items-start`, `lg:items-center`) +2. *Display:* Controls whether an element is shown, hidden, or changes display mode. (e.g., `sm:hidden`, `md:block`, `lg:flex`) +3. *Flex Direction:* Defines the direction of items in a flex container (`row` or `column`). (e.g., `sm:flex-col`, `lg:flex-row`) +4. *Font Size:* Adjusts the text size based on screen size for readability and hierarchy. (e.g., `sm:text-lg`, `lg:text-3xl`) +5. *Grid:* Controls the number of columns in a grid layout depending on screen width. (e.g., `sm:grid-cols-2`, `md:grid-cols-4`) +6. *Position:* Controls the position property (`static`, `sticky`, `absolute`, etc.) responsively. (e.g., `md:sticky`, `lg:fixed`) + +[IMPORTANT] +==== +**What about other utilities like Spacing, Gap, or Justify Content?** + +Common utilities such as `Padding`, `Margin`, `Gap`, and `JustifyContent` **do not currently have responsive breakpoint variants** in the `LumoUtility` Java API. + +To apply responsive styles for these properties, you should use custom CSS with media queries in your application's theme. +This approach gives you full control over the responsive behavior. +==== + +=== Example: Creating Responsive Padding with Custom CSS + +Suppose you want a `Div` to have small padding on mobile devices and large padding on desktops. + +. **Apply a custom class name in Java:** ++ +[.example] +-- +[source,java] +---- +Div responsiveCard = new Div(); +responsiveCard.addClassName("responsive-padding-card"); +// You can still apply non-responsive utilities +responsiveCard.addClassNames(LumoUtility.Background.CONTRAST_5, LumoUtility.BorderRadius.LARGE); +---- +-- + +. **Define the responsive styles in your theme's CSS file (`styles.css`):** ++ +[.example] +-- +[source,css] +---- +/* styles.css */ + +.responsive-padding-card { + /* Default style for mobile */ + padding: var(--lumo-space-s); +} + +/* Apply larger padding on medium screens and up */ +@media (min-width: 768px) { + .responsive-padding-card { + padding: var(--lumo-space-l); + } +} +---- +-- + +== Responsive Utility Examples + +The following sections explore each of the six utility groups that currently offer responsive variants in the `LumoUtility` Java API. + +Each section follows a similar structure to facilitate understanding: +a brief description of the utility, a basic usage example, a list of the available classes, and a complete, practical example demonstrating its application in a real-world scenario. + +== Align Items + +`LumoUtility.AlignItems` controls the alignment of items along the cross axis of a flexbox or the block axis of a grid. + +`LumoUtility.AlignItems.Breakpoint` provides the same alignment options, but scoped to specific viewport sizes. + +=== Basic Breakpoint Usage + +[.example] +-- +[source,java] +---- +// Instantiate a container component +Div container = new Div(); + +// Apply different align-items at different breakpoints +container.addClassNames( + LumoUtility.Display.FLEX, + // align-items: start on small screens + LumoUtility.AlignItems.Breakpoint.Small.START, + // align-items: center on medium screens + LumoUtility.AlignItems.Breakpoint.Medium.CENTER, + // align-items: end on large screens + LumoUtility.AlignItems.Breakpoint.Large.END +); +---- +-- + +The available classes within the `Small`, `Medium`, `Large`, `XLarge`, and `XXLarge` breakpoints are: + +.Available Responsive Align Items Classes +[cols="1,2,2"] +|=== +| Java Constant | CSS class name | Equivalent in CSS + +| `BASELINE` +| `items-baseline` +| `align-items: baseline` + +| `CENTER` +| `items-center` +| `align-items: center` + +| `END` +| `items-end` +| `align-items: flex-end` + +| `START` +| `items-start` +| `align-items: flex-start` + +| `STRETCH` +| `items-stretch` +| `align-items: stretch` +|=== + +Each constant is prefixed with the breakpoint -- for example, `sm:items-center` or `md:items-start`. + +=== Complete Responsive Example + +[.example] +-- +[source,java] +---- +import com.vaadin.flow.component.button.Button; +import com.vaadin.flow.component.html.Div; +import com.vaadin.flow.component.html.H3; +import com.vaadin.flow.theme.lumo.LumoUtility; + +public class ResponsiveAlignItemsExample extends Div { + + public ResponsiveAlignItemsExample() { + H3 title = new H3("Responsive Align Items Example"); + + // Create a responsive flex container + Div responsiveContainer = new Div(); + + responsiveContainer.addClassNames( + // Basic flex setup + LumoUtility.Display.FLEX, + LumoUtility.FlexDirection.COLUMN, + LumoUtility.Padding.MEDIUM, + + // Responsive align-items + + // End on mobile + LumoUtility.AlignItems.END, + // Center on tablet + LumoUtility.AlignItems.Breakpoint.Medium.CENTER, + // Start on desktop + LumoUtility.AlignItems.Breakpoint.Large.START + ); + + // Add content + responsiveContainer.add( + new Button("Button 1"), + new Button("Button 2"), + new Button("Button 3") + ); + + add(title, responsiveContainer); + } +} +---- +-- + +.Responsive align-items example at viewport >= `Breakpoint.Large` (`Breakpoint.Large.START`) +[.fill.white] +image::../_images/align_items_large.png[AlignItems Responsive Breakpoints] + +.Responsive align-items example at viewport >= `Breakpoint.Medium` (`Breakpoint.Medium.CENTER`) +[.fill.white] +image::../_images/align_items_medium.png[AlignItems Responsive Breakpoints] + +.Responsive align-items example at viewport >= `Breakpoint.Small` (`Breakpoint.Small.END`) +[.fill.white] +image::../_images/align_items_small.png[AlignItems Responsive Breakpoints] + +==== Key Points + +1. *Mobile first:* `AlignItems.END` applies at every width, and `Breakpoint.Medium.CENTER` overrides it from 768 pixels upward. +2. *Cascading:* When several breakpoints set alignment, the largest matching one wins -- `Breakpoint.Large.START` overrides `Breakpoint.Medium.CENTER` on screens at least 1024 pixels wide. +3. *Combining:* You can apply breakpoint variants for different properties (`align-items`, `justify-content`, `flex-direction`) to the same element. + +== Display + +`LumoUtility.Display` sets the display property of an element. +It determines whether the element is a block or inline element and how its items are laid out. + +`LumoUtility.Display.Breakpoint` defines the display property of an element, applied only at certain viewport sizes. + +=== Basic Breakpoint Usage + +[.example] +-- +[source,java] +---- +// Instantiate a container component +Div container = new Div(); + +// Apply different display values at different breakpoints +container.addClassNames( + // Hide on small screens + LumoUtility.Display.HIDDEN, + // Show as block on medium screens + LumoUtility.Display.Breakpoint.Medium.BLOCK, + // Show as flex on large screens + LumoUtility.Display.Breakpoint.Large.FLEX +); +---- +-- + +The available classes within the `Small`, `Medium`, `Large`, `XLarge`, and `XXLarge` breakpoints are: + +.Available Responsive Display Classes +[cols="1,2,2"] +|=== +| Java Constant | CSS class name | Equivalent in CSS + +| `BLOCK` +| `block` +| `display: block` + +| `FLEX` +| `flex` +| `display: flex` + +| `GRID` +| `grid` +| `display: grid` + +| `HIDDEN` +| `hidden` +| `display: none` + +| `INLINE` +| `inline` +| `display: inline` + +| `INLINE_BLOCK` +| `inline-block` +| `display: inline-block` + +| `INLINE_FLEX` +| `inline-flex` +| `display: inline-flex` + +| `INLINE_GRID` +| `inline-grid` +| `display: inline-grid` +|=== + +Each constant is prefixed with the breakpoint -- for example, `md:block` or `lg:flex`. + +=== Complete Responsive Example + +[.example] +-- +[source,java] +---- +import com.vaadin.flow.component.button.Button; +import com.vaadin.flow.component.html.Div; +import com.vaadin.flow.component.html.H3; +import com.vaadin.flow.component.html.Span; +import com.vaadin.flow.component.icon.VaadinIcon; +import com.vaadin.flow.theme.lumo.LumoUtility; + +public class ResponsiveDisplayExample extends Div { + + public ResponsiveDisplayExample() { + H3 title = new H3("Responsive Display Example"); + + // Mobile-only message + Div mobileMessage = createMessage(VaadinIcon.MOBILE, "Mobile view active", + LumoUtility.Background.SUCCESS_10); + mobileMessage.addClassNames( + // Show on mobile + LumoUtility.Display.FLEX, + // Hide on tablet and up + LumoUtility.Display.Breakpoint.Medium.HIDDEN, + // Hide on desktop + LumoUtility.Display.Breakpoint.Large.HIDDEN + ); + + // Tablet-only message + Div tabletMessage = createMessage(VaadinIcon.TABLET, "Tablet view active", + LumoUtility.Background.PRIMARY_10); + tabletMessage.addClassNames( + // Hide on mobile + LumoUtility.Display.HIDDEN, + // Show on tablet + LumoUtility.Display.Breakpoint.Medium.FLEX, + // Hide on desktop + LumoUtility.Display.Breakpoint.Large.HIDDEN + ); + + // Desktop-only message + Div desktopMessage = createMessage(VaadinIcon.DESKTOP, "Desktop view active", + LumoUtility.Background.ERROR_10); + desktopMessage.addClassNames( + // Hide on mobile + LumoUtility.Display.HIDDEN, + // Hide on tablet + LumoUtility.Display.Breakpoint.Medium.HIDDEN, + // Show on desktop + LumoUtility.Display.Breakpoint.Large.FLEX + ); + + add(title, mobileMessage, tabletMessage, desktopMessage); + } + + private Div createMessage(VaadinIcon icon, String text, String background) { + Div message = new Div(icon.create(), new Span(text)); + message.addClassNames( + // Center the icon and text, with a gap between them + LumoUtility.AlignItems.CENTER, + LumoUtility.Gap.SMALL, + background, + LumoUtility.Padding.MEDIUM, + LumoUtility.BorderRadius.MEDIUM + ); + return message; + } +} +---- +-- + +.Responsive display example on desktop, at viewport >= `Breakpoint.Large` +[.fill.white] +image::../_images/display_desktop.png[Display Responsive Breakpoints] + +.Responsive display example on tablet, at viewport >= `Breakpoint.Medium` +[.fill.white] +image::../_images/display_tablet.png[Display Responsive Breakpoints] + +.Responsive display example on mobile, below `Breakpoint.Medium` +[.fill.white] +image::../_images/display_mobile.png[Display Responsive Breakpoints] + + +==== Key Points + +1. *Mobile First:* Unprefixed display utilities apply to all screen sizes, while breakpoint variants take effect from their minimum width upward. +2. *Visibility Control:* Use `HIDDEN` to hide elements at specific breakpoints -- for example, showing a full navigation bar on desktop but hiding it on mobile in favor of a menu button. +3. *Layout Switching:* Change between `BLOCK`, `FLEX`, and `GRID` to create different layouts at different screen sizes. + +== Flex Direction + +`LumoUtility.FlexDirection` defines the direction of items in a flex container. +This is extremely useful for switching from a column layout on mobile to a row layout on desktop. + +`LumoUtility.FlexDirection.Breakpoint` allows you to apply different `flex-direction` values at different screen sizes (responsive design). +This is particularly useful for changing layout orientation based on screen size, such as switching from horizontal to vertical layouts. + +=== Basic Breakpoint Usage + +[.example] +-- +[source,java] +---- +// Instantiate a container component +Div container = new Div(); + +// Apply different flex-direction values at different breakpoints +container.addClassNames( + LumoUtility.Display.FLEX, + // Stack vertically on small screens + LumoUtility.FlexDirection.Breakpoint.Small.COLUMN, + // Arrange horizontally on medium screens + LumoUtility.FlexDirection.Breakpoint.Medium.ROW +); +---- +-- + +The available classes within the `Small`, `Medium`, `Large`, `XLarge`, and `XXLarge` breakpoints are: + +.Available Responsive Flex Direction Classes +[cols="1,2,2"] +|=== +| Java Constant | CSS class name | Equivalent in CSS + +| `COLUMN` +| `flex-col` +| `flex-direction: column` + +| `ROW` +| `flex-row` +| `flex-direction: row` +|=== + +Each constant is prefixed with the breakpoint -- for example, `sm:flex-col` or `md:flex-row`. + +=== Complete Responsive Example + +[.example] +-- +[source,java] +---- +import com.vaadin.flow.component.html.Div; +import com.vaadin.flow.component.html.H3; +import com.vaadin.flow.component.html.Span; +import com.vaadin.flow.theme.lumo.LumoUtility; + +public class ResponsiveFlexDirectionExample extends Div { + + public ResponsiveFlexDirectionExample() { + H3 title = new H3("Responsive Flex Direction Example"); + + // Container that changes flex direction based on screen size + Div flexContainer = new Div(); + flexContainer.addClassNames( + // Basic flex setup + LumoUtility.Display.FLEX, + LumoUtility.Gap.MEDIUM, + LumoUtility.Padding.LARGE, + LumoUtility.BorderRadius.MEDIUM, + LumoUtility.Background.CONTRAST_5, + + // Responsive flex-direction + + // Stack on mobile + LumoUtility.FlexDirection.COLUMN, + // Horizontal on tablet + LumoUtility.FlexDirection.Breakpoint.Medium.ROW, + + // Responsive alignment (works with flex-direction changes) + LumoUtility.AlignItems.CENTER, + LumoUtility.AlignItems.Breakpoint.Large.START + ); + + // Add content with indicators + flexContainer.add( + createFlexItem("First", "1", LumoUtility.Background.SUCCESS_10), + createFlexItem("Second", "2", LumoUtility.Background.PRIMARY_10), + createFlexItem("Third", "3", LumoUtility.Background.ERROR_10) + ); + + add(title, flexContainer); + } + + private Div createFlexItem(String text, String number, String bgColor) { + Div item = new Div(); + item.addClassNames( + bgColor, + LumoUtility.Padding.MEDIUM, + LumoUtility.BorderRadius.SMALL, + LumoUtility.Display.FLEX, + LumoUtility.AlignItems.CENTER, + LumoUtility.JustifyContent.CENTER, + LumoUtility.FlexDirection.COLUMN, + LumoUtility.Gap.SMALL + ); + + Span label = new Span(text); + label.addClassName(LumoUtility.FontWeight.BOLD); + + Span numberSpan = new Span("#" + number); + numberSpan.addClassName(LumoUtility.FontSize.SMALL); + + item.add(label, numberSpan); + return item; + } +} +---- +-- + +.Responsive flex-direction example stacked as a column, below `Breakpoint.Medium` +[.fill.white] +image::../_images/flex_direction_column.png[FlexDirection Responsive Breakpoints] + +.Responsive flex-direction example laid out as a row, at viewport >= `Breakpoint.Medium` +[.fill.white] +image::../_images/flex_direction_row.png[FlexDirection Responsive Breakpoints] + + +==== Key Points + +1. *Mobile First:* Use the unprefixed `FlexDirection.COLUMN` as the base for all screen sizes, and override it with breakpoint variants such as `Medium.ROW` from their minimum width upward. +2. *Direction Switching:* Switch between vertical stacking on mobile and horizontal layouts on desktop -- useful for forms that stack on mobile but sit side-by-side on wider screens. +3. *Combine With Other Flex Properties:* `FlexDirection` changes work well alongside responsive `AlignItems`, `JustifyContent`, and `Gap` utilities. +4. *Navigation Patterns:* Useful for responsive navigation, such as a tab bar that runs horizontally on desktop but collapses to a vertical list on mobile. + +== Font Size + +`LumoUtility.FontSize` adjusts the font size of text based on the screen size to improve readability and visual hierarchy. + +`LumoUtility.FontSize.Breakpoint` allows you to apply different `font-size` values at different screen sizes (responsive design). +This is particularly useful for creating typography that scales appropriately across devices, ensuring optimal readability on all screen sizes. + +=== Basic Breakpoint Usage + +[.example] +-- +[source,java] +---- +// Instantiate a container component +Div container = new Div(); + +// Apply different font sizes at different breakpoints +container.addClassNames( + // Large font on small screens + LumoUtility.FontSize.LARGE, + // Extra large on medium screens + LumoUtility.FontSize.Breakpoint.Medium.XLARGE, + // Extra extra large on large screens + LumoUtility.FontSize.Breakpoint.Large.XXLARGE +); +---- +-- + +The available classes within `Small`, `Medium`, `Large`, `XLarge`, and `XXLarge` breakpoints are: + +.Available Responsive Font Sizes +[cols="1,2,2,2"] +|=== +| Java Constant | Description | CSS class name | Equivalent in CSS + +| `XXSMALL` +| Extra extra small text +| `text-2xs` +| `font-size: 0.75rem` + +| `XSMALL` +| Extra small text +| `text-xs` +| `font-size: 0.8125rem` + +| `SMALL` +| Small text +| `text-s` +| `font-size: 0.875rem` + +| `MEDIUM` +| Medium/normal text +| `text-m` +| `font-size: 1rem` + +| `LARGE` +| Large text +| `text-l` +| `font-size: 1.125rem` + +| `XLARGE` +| Extra large text +| `text-xl` +| `font-size: 1.375rem` + +| `XXLARGE` +| Extra extra large text +| `text-2xl` +| `font-size: 1.75rem` + +| `XXXLARGE` +| Extra extra extra large text +| `text-3xl` +| `font-size: 2.5rem` +|=== + +=== Complete Responsive Typography Example + +[.example] +-- +[source,java] +---- +import com.vaadin.flow.component.html.Div; +import com.vaadin.flow.component.html.H1; +import com.vaadin.flow.component.html.H2; +import com.vaadin.flow.component.html.Span; +import com.vaadin.flow.theme.lumo.LumoUtility; + +public class ResponsiveTypographyExample extends Div { + + public ResponsiveTypographyExample() { + // Main heading with significant size changes + H1 mainHeading = new H1("Welcome to Our Platform"); + mainHeading.addClassNames( + // Responsive font sizes + + // Large on mobile + LumoUtility.FontSize.LARGE, + // XXLarge on tablet + LumoUtility.FontSize.Breakpoint.Medium.XXLARGE, + // XXXLarge on desktop + LumoUtility.FontSize.Breakpoint.Large.XXXLARGE, + + // Additional styling + LumoUtility.FontWeight.BOLD, + LumoUtility.TextColor.PRIMARY, + LumoUtility.Margin.NONE, + LumoUtility.Padding.MEDIUM + ); + + // Subtitle with moderate scaling + H2 subtitle = new H2("Discover amazing features and services"); + subtitle.addClassNames( + // Medium on mobile + LumoUtility.FontSize.MEDIUM, + // Large on tablet + LumoUtility.FontSize.Breakpoint.Medium.LARGE, + // XL on desktop + LumoUtility.FontSize.Breakpoint.Large.XLARGE, + + LumoUtility.TextColor.SECONDARY, + LumoUtility.FontWeight.NORMAL, + LumoUtility.Margin.SMALL + ); + + // Body text with subtle scaling + Span bodyText = new Span( + "Our platform offers cutting-edge solutions for modern businesses. " + + "Experience seamless integration, powerful analytics, and intuitive design " + + "that adapts to your needs across all devices." + ); + bodyText.addClassNames( + // Small on mobile + LumoUtility.FontSize.SMALL, + // Medium on tablet+ + LumoUtility.FontSize.Breakpoint.Medium.MEDIUM, + // Large on desktop + LumoUtility.FontSize.Breakpoint.Large.LARGE, + + LumoUtility.TextColor.BODY, + LumoUtility.LineHeight.MEDIUM, + LumoUtility.Padding.MEDIUM + ); + + add(mainHeading, subtitle, bodyText); + } +} +---- +-- + +.Responsive typography example at viewport >= `Breakpoint.Large` +[.fill.white] +image::../_images/font_size_large.png[FontSize Responsive Breakpoints] + +.Responsive typography example at viewport >= `Breakpoint.Medium` +[.fill.white] +image::../_images/font_size_medium.png[FontSize Responsive Breakpoints] + +.Responsive typography example below `Breakpoint.Medium` +[.fill.white] +image::../_images/font_size_small.png[FontSize Responsive Breakpoints] + + +==== Key Points + +1. *Mobile First:* Start with readable mobile sizes and scale up for larger screens, rather than scaling down from a desktop size. +2. *Visual Hierarchy:* Keep the typographic hierarchy consistent across breakpoints -- headings should always be larger than body text. +3. *Content Density:* Mobile screens benefit from slightly smaller body text to fit more content, while desktop can use larger text for better readability. +4. *Accessibility:* Ensure minimum font sizes meet accessibility guidelines (typically 14px or larger for body text). + +== Grid + +`LumoUtility.Grid` defines the number of columns and rows in a grid container. +This is perfect for creating responsive card layouts that adapt to the available space. + +`LumoUtility.Grid.Breakpoint` allows you to apply different CSS Grid properties at different screen sizes (responsive design). +This includes *columns* configurations that adapt to create optimal layouts across devices. + +=== Basic Breakpoint Usage + +[.example] +-- +[source,java] +---- +// Instantiate a container component +Div container = new Div(); + +// Apply different numbers of grid columns at different breakpoints +container.addClassNames( + LumoUtility.Display.GRID, + // 1 column on small screens + LumoUtility.Grid.Column.COLUMNS_1, + // 2 columns on medium screens + LumoUtility.Grid.Breakpoint.Medium.COLUMNS_2, + // 3 columns on large screens + LumoUtility.Grid.Breakpoint.Large.COLUMNS_3, + // 4 columns on extra large screens + LumoUtility.Grid.Breakpoint.XLarge.COLUMNS_4 +); +---- +-- + +The available classes within the `Small`, `Medium`, `Large`, `XLarge`, and `XXLarge` breakpoints range from `COLUMNS_1` to `COLUMNS_12`, for grids of 1 to 12 equal columns: + +.Available Responsive Grid Column Classes +[cols="1,2,2"] +|=== +| Java Constant | CSS class name | Equivalent in CSS + +| `COLUMNS_1` +| `grid-cols-1` +| `grid-template-columns: repeat(1, minmax(0, 1fr))` + +| `COLUMNS_2` +| `grid-cols-2` +| `grid-template-columns: repeat(2, minmax(0, 1fr))` + +| ... (up to) +| ... +| ... + +| `COLUMNS_12` +| `grid-cols-12` +| `grid-template-columns: repeat(12, minmax(0, 1fr))` +|=== + +Each constant is prefixed with the breakpoint -- for example, `md:grid-cols-2` or `lg:grid-cols-3`. + +=== Complete Responsive Grid Example + +[.example] +-- +[source,java] +---- +import com.vaadin.flow.component.html.Div; +import com.vaadin.flow.component.html.H3; +import com.vaadin.flow.component.html.Span; +import com.vaadin.flow.theme.lumo.LumoUtility; + +public class ResponsiveGridExample extends Div { + + public ResponsiveGridExample() { + H3 title = new H3("Responsive Grid Columns"); + + // Grid container with responsive columns and rows + Div gridContainer = new Div(); + gridContainer.addClassNames( + LumoUtility.Display.GRID, + LumoUtility.Gap.MEDIUM, + LumoUtility.Padding.LARGE, + LumoUtility.Background.CONTRAST_5, + LumoUtility.BorderRadius.LARGE, + + // Responsive grid columns + + // 1 column on mobile + LumoUtility.Grid.Column.COLUMNS_1, + // 2 columns on tablet + LumoUtility.Grid.Breakpoint.Medium.COLUMNS_2, + // 3 columns on desktop + LumoUtility.Grid.Breakpoint.Large.COLUMNS_3, + // 4 columns on large desktop + LumoUtility.Grid.Breakpoint.XLarge.COLUMNS_4, + // 6 columns on extra large + LumoUtility.Grid.Breakpoint.XXLarge.COLUMNS_6 + ); + + // Create grid items with different spans + for (int i = 1; i <= 12; i++) { + Div gridItem = createGridItem("Item " + i, i); + + gridContainer.add(gridItem); + } + + add(title, gridContainer); + } + + private Div createGridItem(String title, int index) { + Div item = new Div(); + + // Different background colors for visual distinction + String bgColor = switch (index % 4) { + case 1 -> LumoUtility.Background.SUCCESS_10; + case 2 -> LumoUtility.Background.PRIMARY_10; + case 3 -> LumoUtility.Background.ERROR_10; + default -> LumoUtility.Background.CONTRAST_10; + }; + + item.addClassNames( + bgColor, + LumoUtility.BorderRadius.MEDIUM, + LumoUtility.Padding.LARGE, + LumoUtility.Display.FLEX, + LumoUtility.AlignItems.CENTER, + LumoUtility.JustifyContent.CENTER, + LumoUtility.Height.LARGE + ); + + item.add(new Span(title)); + return item; + } +} +---- +-- + +.Responsive grid example with four columns, at viewport >= `Breakpoint.XLarge` +[.fill.white] +image::../_images/grid_extra_large.png[Grid Responsive Breakpoints] + +.Responsive grid example with two columns, at viewport >= `Breakpoint.Medium` +[.fill.white] +image::../_images/grid_medium.png[Grid Responsive Breakpoints] + +.Responsive grid example with a single column, below `Breakpoint.Medium` +[.fill.white] +image::../_images/grid_small.png[Grid Responsive Breakpoints] + +==== Key Points + +1. *Mobile First:* Start with a single column layout using the unprefixed `Grid.Column.COLUMNS_1`, and expand for larger screens with breakpoint variants such as `Medium.COLUMNS_2` and `Large.COLUMNS_3`. +2. *Column Spans:* Use the non-responsive `Grid.Column.COLUMN_SPAN_*` classes to make a single item span multiple columns -- for example, a chart or summary card that should be wider than the surrounding cards in a dashboard. +3. *Auto-Placement:* Grid automatically places items in available cells, making it easy to add or remove content without breaking the layout. + +== Position + +`LumoUtility.Position` controls the position property of an element, enabling advanced layouts like fixed sidebars on desktop that are part of the normal flow on mobile. + +`LumoUtility.Position.Breakpoint` allows you to apply different CSS positioning properties at different screen sizes (responsive design). +This includes positioning types, directional offsets, and negative positioning that adapt to create optimal layouts and overlays across devices. + +=== Basic Breakpoint Usage + +[.example] +-- +[source,java] +---- +// Instantiate a container component +Div container = new Div(); + +// Apply different position values at different breakpoints +container.addClassNames( + // Relative positioning on small screens + LumoUtility.Position.RELATIVE, + // Absolute positioning on medium screens + LumoUtility.Position.Breakpoint.Medium.ABSOLUTE, + // Fixed positioning on large screens + LumoUtility.Position.Breakpoint.Large.FIXED +); +---- +-- + +The available classes within the `Small`, `Medium`, `Large`, `XLarge`, and `XXLarge` breakpoints are: + +.Available Responsive Position Classes +[cols="1,2,2"] +|=== +| Java Constant | CSS class name | Equivalent in CSS + +| `ABSOLUTE` +| `absolute` +| `position: absolute` + +| `FIXED` +| `fixed` +| `position: fixed` + +| `RELATIVE` +| `relative` +| `position: relative` + +| `STATIC` +| `static` +| `position: static` + +| `STICKY` +| `sticky` +| `position: sticky` +|=== + +Each constant is prefixed with the breakpoint -- for example, `md:sticky` or `lg:fixed`. + +=== Complete Responsive Position Example + +[.example] +-- +[source,java] +---- +import com.vaadin.flow.component.button.Button; +import com.vaadin.flow.component.html.Div; +import com.vaadin.flow.component.html.H3; +import com.vaadin.flow.component.html.Span; +import com.vaadin.flow.theme.lumo.LumoUtility; +import com.vaadin.flow.component.icon.VaadinIcon; + +public class ResponsivePositionExample extends Div { + + public ResponsivePositionExample() { + H3 title = new H3("Responsive Position Example"); + + // Container with relative positioning + Div container = new Div(); + container.addClassNames( + LumoUtility.Position.RELATIVE, + LumoUtility.Background.CONTRAST_5, + LumoUtility.Height.XLARGE, + LumoUtility.Width.FULL, + LumoUtility.BorderRadius.LARGE, + LumoUtility.Margin.LARGE + ); + + // Main content + Div mainContent = new Div("Main Content Area"); + mainContent.addClassNames( + LumoUtility.Background.BASE, + LumoUtility.Padding.LARGE, + LumoUtility.BorderRadius.MEDIUM, + LumoUtility.Height.LARGE, + LumoUtility.Display.FLEX, + LumoUtility.AlignItems.CENTER, + LumoUtility.JustifyContent.CENTER + ); + + // Floating action button - responsive positioning + Button fab = new Button(VaadinIcon.ENVELOPE_O.create()); + fab.addClassNames( + // Position types change with screen size + + // On mobile, keep it in the normal document flow to avoid overlap issues + LumoUtility.Position.RELATIVE, + // On tablets and up, float it over the content + LumoUtility.Position.Breakpoint.Medium.ABSOLUTE, + + // --- Position offsets (only apply when position is absolute/fixed) --- + LumoUtility.Position.Bottom.MEDIUM, + LumoUtility.Position.End.MEDIUM, + + // Styling + LumoUtility.Background.PRIMARY, + LumoUtility.TextColor.PRIMARY_CONTRAST, + LumoUtility.BorderRadius.FULL, + LumoUtility.Width.LARGE, + LumoUtility.Height.LARGE, + LumoUtility.BoxShadow.LARGE + ); + + // Notification banner - responsive positioning + Div notification = new Div(VaadinIcon.BELL_O.create(), new Span("New updates available!")); + notification.addClassNames( + // Changes from static to sticky to fixed + + // On mobile, it's just a static block at the top + LumoUtility.Position.STATIC, + // On tablets, it sticks to the top when you scroll + LumoUtility.Position.Breakpoint.Medium.STICKY, + // On desktops, it's always fixed to the top of the viewport + LumoUtility.Position.Breakpoint.Large.FIXED, + + // Position when fixed/sticky + + // Top of viewport + LumoUtility.Position.Top.NONE, + // Left edge + LumoUtility.Position.Start.NONE, + + // Styling -- flex row so the icon and text sit together with a gap + LumoUtility.Display.FLEX, + LumoUtility.AlignItems.CENTER, + LumoUtility.JustifyContent.CENTER, + LumoUtility.Gap.SMALL, + LumoUtility.Background.SUCCESS, + LumoUtility.TextColor.SUCCESS_CONTRAST, + LumoUtility.Padding.MEDIUM, + LumoUtility.Width.FULL, + LumoUtility.BoxShadow.MEDIUM + ); + + container.add(mainContent, fab); + add(title, notification, container); + } +} +---- +-- + +In the example above, the floating action button stays in the normal document flow on mobile (`RELATIVE`) to avoid overlapping content, and floats over the content on tablets and larger (`ABSOLUTE`). +The notification banner scrolls with the page on mobile (`STATIC`), sticks to the top while scrolling on tablets (`STICKY`), and is pinned to the top of the viewport on desktop (`FIXED`). + +.Responsive position example at viewport >= `Breakpoint.Large`, banner fixed and button floating +[.fill.white] +image::../_images/position_large.png[Position Responsive Breakpoints] + +.Responsive position example at viewport >= `Breakpoint.Medium`, banner sticky and button floating +[.fill.white] +image::../_images/position_medium.png[Position Responsive Breakpoints] + +.Responsive position example below `Breakpoint.Medium`, banner and button in the normal flow +[.fill.white] +image::../_images/position_small.png[Position Responsive Breakpoints] + +==== Key Points + +1. *Position Type Changes:* Elements can change position type across breakpoints -- for example, a "back to top" button that scrolls with the content on mobile (`RELATIVE`) but is pinned to a corner on desktop (`FIXED`). +2. *Mobile First:* Keep elements in the normal document flow on mobile (`RELATIVE`, `STATIC`) and add positioned overlays on larger screens, where there is more room. +3. *Positioning Context:* `ABSOLUTE` and `FIXED` elements are placed relative to their nearest positioned ancestor, so give that container `RELATIVE` positioning to control where they land. +4. *Accessibility:* Ensure positioned elements don't obstruct important content and remain reachable with keyboard navigation. + +== Conclusion + +Lumo’s responsive breakpoint utilities offer a structured and consistent way to adapt layouts and styles across different device sizes directly from Java code. +By leveraging the six supported groups -- `AlignItems`, `Display`, `FlexDirection`, `FontSize`, `Grid`, and `Position` -- developers can create responsive, mobile-first designs without writing custom media queries. + +Keep in mind the following best practices: + +* Start with a **mobile-first** approach and progressively enhance for larger screens. +* **Combine utilities** carefully to maintain readability and consistent layout behavior. +* **Test across devices** and use browser developer tools to validate responsiveness. +* For utilities not yet covered by breakpoints (such as `Padding`, `Margin`, `Gap`, or `JustifyContent`), extend your theme with **custom CSS** media queries. + +For a complete overview of all available utility classes, refer to the main <> documentation.