Once UI in practice — how a backend engineer finally builds frontends he wants to look at
I was never a designer. Tables, forms, service layers — fine. But the moment it came to spacing, hierarchy, and colour, I started guessing. With Once UI that guessing stopped overnight.
I was never a designer. Seven years of Java, Spring, databases, and architecture — anything that lives behind a surface, I could do. The moment it became about the surface, the awkward guessing started: are 16 pixels too many here? Should the button be rounded or square? Which grey doesn't look cheap? The frontends I built in my first six years worked — but I rarely enjoyed looking at them.
Three weeks ago I migrated this site from a Vite + Tailwind combination to Next.js 16 with Once UI. Only then did I realise what I had been missing all along: not an eye for design, but a system that pre-decided the calls I'm not competent to make.
What Once UI is — and what it isn't
Once UI is a React/Next.js component library from the Once Magazine team. It ships geometric primitives (<Column>, <Row>, <Grid>), content components (<Heading>, <Text>, <Button>, <Card>), and a theming system built on CSS custom properties. It's actively developed — I moved from 1.6 to 1.7 mid-migration and nothing broke.
Important to understand: Once UI is not a page builder and not an all-in-one kit like Material UI. If you need filterable tables, datepicker dialogs, or complex forms, you're building them yourself or pairing with a second library. What Once UI gives you is exactly what I had been missing: a grammar for the surface.
What makes the difference as a backend engineer
Spacing tokens. Spacing in Once UI is a discrete scale — 0, 1, 2, 4, 8, 12, 16, 20, 24, 32, 40, 48, 56, 64, 80, 104, 128, 160. Write gap="6" and you get a TypeScript error: doesn't exist. At first this strictness annoyed me. Then I realised what it actually does: it removes the only call I always lost on when building frontends — which number is the right one. The answer is: one of the allowed ones. Done.
Theming as a data attribute. A single data-brand and data-accent attribute on <html> swaps the entire colour palette. The two colours of this site (blue as brand, indigo as accent) are defined once in the configuration file and referenced throughout the codebase via --brand-on-background-strong, --brand-alpha-weak, and similar custom properties. Want the whole site green tomorrow? One-line change.
The layout primitives. Once UI skips Tailwind-style utility classes. Instead I write markup like this:
<Column gap="24" padding="32" maxWidth="m">
<Heading variant="display-strong-l">Headline</Heading>
<Text onBackground="neutral-medium">Description</Text>
</Column>That's no longer flex flex-col items-stretch gap-6 p-8 max-w-2xl — it's structured content. After three days I'm writing frontends I can read without opening a stylesheet next to them.
Where it still chafed
Honestly, because anyone else migrating will hit the same bumps:
- Responsive props aren't reactive everywhere. The
hideprop and similar conditional props work — but at breakpoints that didn't always match my expectations. For the header switch between desktop and mobile, I ended up writing plain CSS media queries. Faster than reverse-engineering the library internals. - Theme init without FOUC takes care. To stop dark mode from flashing light for 200 ms, a tiny inline script must run before hydration. The recommended place is the root layout — not the nested locale layout I tried first. A full walkthrough of that stumble is in my migration post (linked below).
- Learn the spacing scale. For three days I checked the TypeScript error list every other
gapvalue to remember which step was next. Now the scale lives in my head.
The big win: I trust the result
Before Once UI I built frontends I hoped someone would like — but rarely felt confident about. Today I send mockups and don't think "is this too much padding?" or "do these colours look cheap?". The guardrails are built in. A layout built in Once UI with the standard token scale doesn't look like a hobby build.
For a backend engineer that's a release. I can focus on what I can do — architecture, data, logic — and the frontend carries itself, without me simulating designer intuition for two days per section.
Who Once UI is for
Exactly people like me: backend or full-stack engineers who want to build a marketing site, a portfolio, or a product surface without drifting into the designer role. It saves the mechanical work (layout, spacing, theme) without forcing you into a visual identity that isn't yours.
The site you're reading is the reference. If you stop scrolling for a moment — Hero, Audiences spotlight, Pricing cards — you're looking at Once UI plus a layer of my own SCSS modules. That's all it is, and for someone without a design background it's the most honest tool I've ever worked with.
If you want the concrete migration story — what actually broke when moving from Vite + Tailwind to Next.js 16 with Once UI — head to the migration post. That covers the how. This one was about the why.