05Field logFrontendComponentsField log

A field log on the buttons I have shipped, the buttons I have deleted, and what I have learned along the way.

By Tomiwa FolorunsoPublished FEBRUARY 08, 2026Read 4 min

I have written, on a generous count, forty-seven different button components in my career.

I am not proud of this.

The lifecycle of a button

It always starts the same way. Project kickoff, day one. We don't need a UI library, we'll just hand-roll a few primitives. Famous last words.

Day three: there are three buttons. Day ten: there are eleven. Day thirty: someone asks why the disabled state on the danger button looks different from the disabled state on the primary button. Nobody knows. Day forty-five: a junior engineer adds an is-rounded prop. Day sixty: someone makes a Notion page called "Button Audit Q2".

What I have learned

The button is the smallest possible unit of every design system, and yet it carries every single one of the system's contradictions. Color tokens, spacing tokens, typography tokens, animation tokens, focus rings, loading states, icon alignment, semantic HTML, accessibility — all of it lives inside something that, on the surface, is a small rectangle that does a thing when you click it.

If you can ship a button you're proud of in week one, you can ship anything in month three.

The button is the spec test for your design system. It will tell you, in the first ten minutes of writing it, whether your tokens hold up.

The current generation

The button on this site is the forty-seventh. It has:

  • Three variants — but they share 80% of their styling
  • Two sizes — but they're driven by typography, not arbitrary heights
  • One focus ring — applied via :focus-visible, which respects keyboard intent
  • One loading state — that doesn't shift layout when it appears

I will probably write another one next year.

— Filed under
FrontendComponentsField log