Poll: What LumoUtility classes do you use the most?

I’m doing a bit of research on how we could improve on utility classes in Flow, and the styling API in general, and I’d like to hear what parts of LumoUtility you use the most in your projects.

I don’t need specific classes, just the category, such as Background, FontSize, Flex, Padding, etc)

Feel free to also mention if there are things you feel are missing in LumoUtility.

I checked two projects from us:

  • Flex, Alignment, FontSize, Gap, Padding, Margin, Background, Border, Display, Width, FlexWrap, FlexDirection, Text color, Text alignment

Looks very similar here. Mostly about fonts and spacing, ordering and alignment…
If you want it tad more detailed I’ll grep through the sources here :wink:

Most used

  • Flex, FlexDirection, FontSize, FontWeight, Margin, Overflow, Padding,

Nice to have

  • FontStyle, Aura support😜

Don’t mind if you do, if it’s not too much trouble.

I didn’t see the “utility classes in Flow” part initially, so here is my ai summary for Hilla… :slight_smile:

Lumo Utility Classes Usage in /src/main/frontend/views

Category Approx. Usage Notes
Spacing ~200 By far the largest category. Padding (p-s, p-xs, pt-0) and margin reset (m-0) make up the bulk
Flexbox ~130 flex-col, flex-row, flex-wrap are the workhorses for layout
Typography ~70 text-xs and font-bold lead, used for labels, badges, and metadata
Alignment & Positioning ~55 items-center, items-stretch, self-start for component-level alignment
Background & Sizing ~35 bg-contrast-5 for subtle backgrounds, w-full for full-width containers

Not at all, as I can use claude to grep and count through :smiley:

it is not that heavily used as I thought, as we mainly try to focus on style sheets, so it is used more as a “quick fix”.

In two not too big projects we have

Spacing (Padding/Margin/Gap): 15
Padding.SMALL/.Top/.Horizontal, Margin.NONE/.MEDIUM/.Bottom, one Gap.SMALL;
small ad-hoc nudges, not systematic layout

Typography (FontSize/FontWeight/TextColor): 13
FontSize.MEDIUM/.XSMALL and FontWeight.SEMIBOLD/.MEDIUM dominate;
TextColor.HEADER/.SECONDARY only in one project

Background & Sizing (Width/Height/IconSize): 7
almost entirely Width.FULL/.XSMALL for fixed-width columns; one Height.MEDIUM, one IconSize.SMALL

Flexbox (Flex/Display): 5
Flex.GROW/.SHRINK to control column sizing inside HorizontalLayout; one Display.FLEX

Alignment & Positioning (AlignItems/JustifyContent): 4
AlignItems.CENTER/.STRETCH, one JustifyContent.CENTER

Soo, I don’t want to miss it, but it is not our general styling tool ;)

Cheers
Mojo

# LumoUtility Usage Report

Counts of `LumoUtility.*` constant references in `src/main/java` (Voluntarix, 2026-08-15).

## By Category

| Category | Total uses | Most common constants |
|---|---:|---|
| Margin | 235 | `NONE` (74), `Bottom.SMALL` (53), `Bottom.MEDIUM` (52) |
| TextColor | 137 | `SECONDARY` (87), `ERROR` (21), `SUCCESS` (11) |
| FontSize | 78 | `SMALL` (32), `XLARGE` (5), `LARGE` (3) |
| Padding | 45 | `MEDIUM` (20), `SMALL` (6), `LARGE` (4) |
| FontWeight | 41 | `SEMIBOLD` (23), `MEDIUM` (10), `BOLD` (8) |
| Background | 40 | `CONTRAST_5` (15), `ERROR_10` (7), `PRIMARY_10` (6) |
| TextAlignment | 34 | `CENTER` (34) |
| BorderRadius | 28 | `MEDIUM` (22), `SMALL` (5), `FULL` (1) |
| IconSize | 8 | `SMALL` (3), `MEDIUM` (3), `LARGE` (2) |
| Gap | 8 | `SMALL` (4), `MEDIUM` (4) |
| Display | 6 | `BLOCK` (4), `FLEX` (2) |
| Border | 5 | `ALL` (5) |
| Width | 2 | `FULL` (2) |
| AlignItems | 2 | `CENTER` (2) |
| BorderColor | 2 | `PRIMARY` (1), `CONTRAST_20` (1) |
| JustifyContent | 1 | `BETWEEN` (1) |

## Full Ranking

| Rank | Constant | Uses |
|---:|---|---:|
| 1 | `TextColor.SECONDARY` | 87 |
| 2 | `Margin.NONE` | 74 |
| 3 | `Margin.Bottom.SMALL` | 53 |
| 4 | `Margin.Bottom.MEDIUM` | 52 |
| 5 | `TextAlignment.CENTER` | 34 |
| 6 | `FontSize.SMALL` | 32 |
| 7 | `FontWeight.SEMIBOLD` | 23 |
| 8 | `BorderRadius.MEDIUM` | 22 |
| 9 | `TextColor.ERROR` | 21 |
| 10 | `Padding.MEDIUM` | 20 |
| 11 | `Margin.Bottom.LARGE` | 18 |
| 12 | `Background.CONTRAST_5` | 15 |
| 13 | `Margin.Top.LARGE` | 14 |
| 14 | `Margin.Top.MEDIUM` | 12 |
| 15 | `TextColor.SUCCESS` | 11 |
| 16 | `FontWeight.MEDIUM` | 10 |
| 17 | `FontWeight.BOLD` | 8 |
| 18 | `TextColor.PRIMARY` | 7 |
| 19 | `Background.ERROR_10` | 7 |
| 20 | `TextColor.TERTIARY` | 6 |
| 21 | `Padding.SMALL` | 6 |
| 22 | `Background.PRIMARY_10` | 6 |
| 23 | `TextColor.WARNING` | 5 |
| 24 | `FontSize.XLARGE` | 5 |
| 25 | `BorderRadius.SMALL` | 5 |
| 26 | `Border.ALL` | 5 |
| 27 | `Background.WARNING_10` | 5 |
| 28 | `Padding.LARGE` | 4 |
| 29 | `Margin.Top.SMALL` | 4 |
| 30 | `Margin.Top.NONE` | 4 |
| 31 | `Margin.Bottom.XSMALL` | 4 |
| 32 | `Gap.SMALL` | 4 |
| 33 | `Gap.MEDIUM` | 4 |
| 34 | `Display.BLOCK` | 4 |
| 35 | `Padding.XLARGE` | 3 |
| 36 | `Padding.Left.NONE` | 3 |
| 37 | `Padding.Horizontal.SMALL` | 3 |
| 38 | `Margin.Right.SMALL` | 3 |
| 39 | `IconSize.SMALL` | 3 |
| 40 | `IconSize.MEDIUM` | 3 |
| 41 | `FontSize.LARGE` | 3 |
| 42 | `Width.FULL` | 2 |
| 43 | `Padding.Vertical.NONE` | 2 |
| 44 | `Margin.Left.SMALL` | 2 |
| 45 | `Margin.Bottom.XLARGE` | 2 |
| 46 | `IconSize.LARGE` | 2 |
| 47 | `FontSize.XSMALL` | 2 |
| 48 | `Display.FLEX` | 2 |
| 49 | `Background.SUCCESS_10` | 2 |
| 50 | `Background.CONTRAST_20` | 2 |
| 51 | `Background.BASE` | 2 |
| 52 | `AlignItems.CENTER` | 2 |
| 53 | `Padding.Vertical.XSMALL` | 1 |
| 54 | `Padding.Top.SMALL` | 1 |
| 55 | `Padding.Right.SMALL` | 1 |
| 56 | `Padding.Right.MEDIUM` | 1 |
| 57 | `Padding.Horizontal.XSMALL` | 1 |
| 58 | `Padding.Horizontal.MEDIUM` | 1 |
| 59 | `Padding.Horizontal.LARGE` | 1 |
| 60 | `Margin.Left.XSMALL` | 1 |
| 61 | `Margin.Horizontal.NONE` | 1 |
| 62 | `Margin.Horizontal.AUTO` | 1 |
| 63 | `JustifyContent.BETWEEN` | 1 |
| 64 | `FontSize.XXLARGE` | 1 |
| 65 | `FontSize.MEDIUM` | 1 |
| 66 | `BorderRadius.FULL` | 1 |
| 67 | `BorderColor.PRIMARY` | 1 |
| 68 | `BorderColor.CONTRAST_20` | 1 |
| 69 | `Background.CONTRAST` | 1 |

## Takeaway

The dominant styling idiom in the views is: `TextColor.SECONDARY` + `FontSize.SMALL` for captions and helper text, `Margin.NONE` to reset heading defaults, and `Margin.Bottom.SMALL`/`MEDIUM` for vertical rhythm. Background tints (`CONTRAST_5`, `*_10`) with `BorderRadius.MEDIUM` form the card/badge surface pattern.

1 Like

Big thanks to everyone – this was super insightful!

Followup questions:

  1. Why are you using FlexBox utility classes instead of HorizontalLayout and VerticalLayout?

  2. Are gap, padding and margin used primarily for flexboxes and/or HL+VL? Or for something else?

  3. For those who use Width.FULL, why use that instead of setWidthFull()?

  4. For those who use Flex.GROW/SHRINK, why use that instead of setFlexGrow/Shrink (on layouts)?

(and to @SimonMartinelli , I presume margin-resets on headings is in an older version of Vaadin, as both themes have zero margins on headings these days?)

Hi @rofa
I took the largest Vaadin application and yes the origin was an older Vaadin version.

  1. HL and VL feel heavy compared to a lightweight div or flex layout. Especially when nested shadow doms were expensive for Browsers…

  2. gaps, yes. margins and paddings on the other hand are literally used everywhere

  3. setWidthfull uses inline styles - I don’t like inline styles.

  4. at least the examples I remember… convenience. It was easier to apply it at the component instead of thinking about it 3 layers later at the Layout Level

1 Like

I am with knoobie here, and especially underlining his point 4 :upside_down_face:

One can say:
LumoUtility gives me Lumo’s own predefined, design-token-consistent class — addressed as a type-checked Java constant, not a raw string — that travels with the component and stays overridable.

The Java-API equivalent instead ties the code to a specific parent-layout reference (setFlexGrow) or bakes an inline style straight onto the element that’s hard to undo later (setWidthFull).

PS: post was created with the help of AI :grin:

Cheers
Mojo

Thanks @knoobie and @m0j0. Naturally I have followups to the followups:

Have you noticed performance difference between HL/VL and divs with classes recently? I think the difference is very marginal these days, unless you have hundreds of instances on the page.

Do you also use native button elements instead of the Button class (which also has shadow DOM)?

Is your aversion to inline styles (as produced by setWidthFull etc) specifically that they’re not easily overridable in stylesheets, or something else as well?

Regarding the overridability of inline size styles, what scenarios would you have that in?

Have you noticed performance difference between HL/VL and divs with classes recently?

All my larger application are pretty “old” and are build with this mindset, so I don’t have a good app to test it

Do you also use native button elements instead of the Button class (which also has shadow DOM)?

No, because I heavily rely on setDisableOnClick - the most crucial Feature IMHO in business applications.

Is your aversion to inline styles (as produced by setWidthFull etc) specifically that they’re not easily overridable in stylesheets, or something else as well?

Personal taste nothing more really. And the academic problem when using a really draconic CSP

If the CSP is blocking inline styles, doesn’t that wreak havoc on quite a lot of Vaadin features?

Yes :) that’s why I added “academic” - such a CSP would kill Vaadin apps as a whole

Thanks for the follow-follow-ups! :grin:

Performance: agree it’s marginal these days. Not a problem.

Native button: no, we default to the regular Button almost exclusively — not for a specific reason but really just as default.

Inline styles: Similar to knoobie, personal taste and readability for me. And keeping the override door open “just in case” feels safer. Plus the CSP argument counts.

Cheers
Mojo

Thanks @m0j0. I’ll still nitpick at bit about the inline styles if you don’t mind.

Both of you have a “personal preference” against inline styles, and I guess I’m surprised that you care what the resulting HTML looks like, and curious why. (Not critical, really just curious.)

I’m also a bit confused now as it seems the CSP both is and isn’t an issue: on one hand, it’s good to avoid inline styles because if you run the app with a strict CSP they might get blocked; on the other, if the CSP is that strict, the whole app will likely be broken?

Also I’d still really like to hear of cases where you’d want to override a sizing style set in once place, instead of just changing it where it’s set. Responsive? Something else?

(and yes, I realize I’m starting to sound like a five year old, asking “Why??” whenever you answer :sweat_smile: )

Will try to answer this :joy:

About “personal preference”: it’s less about how the rendered HTML looks, and more about how the Java code reads — a chain of LumoUtility classes tends to read cleaner to us than an inline style string
built up in code. A technical reason: inline style=“…” almost always “wins” over normal CSS rules, no matter what. So if a component sets a size that way, nobody who comes after — a theme, a dark mode, another team reusing that component — can change it with regular CSS. They’d need !important, generally seen as a last resort.

CSP: sorry, was perhaps too vague. It’s not “no CSS allowed” — it’s specifically about the inline style=“…” attribute being blocked. Our own regular CSS files would still load and work fine under that same strict setting. Just to add: we yet doesn’t have any CSP app around, but who knows…

Overriding: “Mr. claude” gave me 2 examples as my EN knowledge describing what I want to say is out for today :smiley:

  • @media queries — only work inside a real stylesheet. Inline style=“…” is just a flat list of properties, no selector/at-rule syntax exists there, so responsive breakpoints can’t be expressed that way at all.
  • Pseudo-classes/elements (:hover, :focus, ::part() for theming inside a component’s shadow DOM) — same root cause: inline style has nothing to attach a selector to, so these simply don’t exist as an inline option either

Cheers
Mojo

more about how the Java code reads — a chain of LumoUtility classes tends to read cleaner to us than an inline style string built up in code

Sure, but I was thinking about things for which there is no need to use inline style strings at all, things for which there are dedicated java APIs, like VL & HL, sizing and alignment APIs, etc. Is a list of string constants better than those?

if a component sets a size that way, nobody who comes after — a theme, a dark mode, another team reusing that component — can change it with regular CSS

That is true. I suppose I just feel that applying styling this way is a recipe for disaster: you now have two different places where that style is set: one with a utility class, and another from a stylesheet somewhere. Debugging that is not fun. CSS custom properties or dedicated APIs on the component would be much less spaghetti. Light/dark can be handled cleanly with just CSS rather than overriding.

The same applies to media queries: if you use media queries it is much better for maintainability to always apply those styles through them, instead of overriding.

The pseudo-class/element case is irrelevant in this case as LumoUtility has no such classes.

All that being said, the overridability aspect is something I had not taken into account at all, so I’m glad it came up, and I will take note of it.

It’s not “no CSS allowed” — it’s specifically about the inline style=“…” attribute being blocked.

I understood that, but blocking inline styles in general will also break a lot of Vaadin features, not just sizing APIs.

(by the way, I’m fine with replies in German too :slight_smile: )

1 Like