← Blog
engineeringindie devuifrontend

Working Without a Designer

23 March 2026

Working Without a Designer

I'm not a designer. I can recognize good UI, I can articulate why something feels off, but I don't have the instincts that come from years of thinking visually. Left to my own devices, I will spend forty-five minutes choosing between two shades of gray and end up with neither.

For a long time I treated this as a gap to close — something I'd get better at if I just read enough articles about typography and spacing and visual hierarchy. That was the wrong frame. The better question isn't how to become a better designer. It's how to make as few design decisions as possible.

What a designer actually gives you

It's not just taste. A designer gives you a system — a consistent set of rules that govern spacing, color, type, and interaction. Once those rules exist, most UI decisions resolve automatically. You don't choose between sizes; you pick from a scale. You don't choose a color; you pick a token from a palette with a defined role.

When there's no designer, there's no system. And without a system, every component becomes a new negotiation. Should this heading be 20px or 22px? Should there be 16px of padding or 20px? Should the border radius match the card or the button? These decisions feel small individually. They compound fast, and inconsistency accumulates in ways that make a product feel unpolished without anyone being able to say exactly why.

The solo developer's problem isn't that they make bad design decisions. It's that they have to make too many of them.

Trust the framework

The solution I've arrived at is to trust a design system almost blindly. Not because every decision a framework makes is the right one, but because consistent wrong decisions are better than inconsistent ones. A button that's slightly too small across every screen looks considered. A button that's slightly too small on three screens and slightly too large on two looks broken.

This means accepting the system's constraints rather than fighting them. When a framework gives you a spacing scale, use the scale — don't reach for arbitrary pixel values because something looks slightly off. When it gives you a color palette, use the palette. The moment you start overriding things piecemeal, you've left the system, and you're on your own.

How I got here on the web

My first real project used Material UI. It was the obvious choice at the time — a complete component library, every piece you could need, with Google's design language baked in. The velocity was real. You could build a functional, reasonably coherent interface quickly without making many decisions at all. The problem came later, when the product needed to look like itself rather than like a Material Design app. Getting MUI out of its own way required fighting it at every step.

I moved to Mantine, which is more flexible and more pleasant to work with. The components are well-designed, the documentation is excellent, and it doesn't impose quite the same visual identity. But I kept running into the same fundamental tension: a component library is someone else's abstraction over CSS, and that abstraction has edges. Every time I needed something slightly off the happy path, I was reading source code and writing overrides.

Tailwind resolved this by moving the abstraction to a lower level. It doesn't give you components — it gives you a constrained set of primitives. A spacing scale, a type scale, a color palette. The decisions are still limited, but the composition is yours. There are no components to fight, no override mechanisms to understand. You build what you need using values the system has already chosen, and the result is consistent because the primitives are consistent.

The same pattern, repeated on mobile

On React Native, I went through a nearly identical arc. I used UI Kitten and React Native Paper — both solid, both coherent design systems, both component-first. The same tradeoffs applied: fast to start, friction to customize, increasingly awkward when the product's needs diverged from the library's assumptions.

NativeWind brought the Tailwind model to React Native — the same utility-first approach, the same constraints applied through a shared design language. The shift felt familiar because it was the same move: from "use our components" to "use our scale."

The trap you avoid

There's a version of this that goes wrong. The developer decides they know better than the framework and starts overriding things — custom spacing values here, one-off colors there, a component that bends the library's rules because the design called for something slightly different. Six months later, the UI is inconsistent in ways that are hard to trace, because the system's rules no longer apply uniformly.

The value of a design system isn't any individual decision it makes. It's the uniformity. Violate enough of the rules and you no longer have a system — you have a collection of ad-hoc choices that happen to share a component library.

When I accepted that my job was to stay inside the constraints rather than escape them, the UI got better without me becoming a better designer. The work shifted from making decisions to making things. That's where I want to spend the time.

The constraint is the feature

Working without a designer means accepting that you won't produce design-forward interfaces. What you can produce is consistent, functional, coherent UI — if you pick a system and commit to it.

The choice of system matters less than the commitment to it. What breaks consistency isn't picking the wrong framework. It's picking the right one and then deciding you know better.