If your button has more than one job, it's not a button anymore

4 min read 1 source clear_take
├── "A button is a state machine, not a rectangle — its job is to communicate its state at every instant"
│  └── Marcin Wichary (unsung.aresluna.org) → read

Wichary argues that buttons feel broken not because of visual regressions but because engineers fail to model them as publicly observable state machines. A button's entire job is to communicate whether it can be pressed, whether it is being pressed, and what will happen if pressed — treating it as decoration for an action rather than the action's user-facing contract is the root cause of most UX failures.

├── "The real state space of a button is far larger than engineers typically enumerate"
│  ├── Marcin Wichary (unsung.aresluna.org) → read

Wichary points out that mid-level engineers typically list four states (default, hover, active, disabled), when the real list is closer to a dozen including focus-visible, disabled-because-form-invalid, disabled-because-request-in-flight, loading, and transient success/error states. Most shipped UI bugs — double-fires, clickable spinners, unexplained disabled states — trace back to states that were never explicitly written down.

│  └── @nozzlegear (Hacker News, 514 pts) → view

By submitting the essay to Hacker News where it reached 514 points, nozzlegear amplified the argument that button state modeling is a widely under-appreciated engineering problem. The strong community response signals broad recognition that the enumerated-states framing captures a real gap in how buttons are built.

├── "Disabled buttons must explain WHY they are disabled, not just visually gray out"
│  └── Marcin Wichary (unsung.aresluna.org) → read

Wichary highlights that disabled buttons which give no reason for being disabled are a common failure mode — the state is communicated but the causation isn't. A button's contract with the user includes explaining what would need to change for it to become pressable, which most implementations silently omit.

└── "Visual dominance of primary buttons can override user intent, making them a UX liability"
  └── Marcin Wichary (unsung.aresluna.org) → read

Wichary notes that primary buttons which visually dominate a modal can cause users to click them reflexively without reading the surrounding content. This inverts the button's proper role: instead of communicating an action, it coerces one, which is a violation of the single-job principle.

What happened

An essay titled "If you're a button, you have one job" hit 514 points on Hacker News, written by Marcin Wichary on his site unsung.aresluna.org. Wichary — who literally wrote the book on keyboards (*Shift Happens*, ~1,200 pages on the history of the typewriter) — spends the piece dissecting why so many buttons on the modern web are broken, and why the fix isn't visual polish but a clearer mental model of what a button actually *is*.

His argument, stripped to its bones: a button is not a rectangle with a label. A button is a small, publicly observable state machine whose entire job is to communicate, at every instant, whether it can be pressed, whether it is being pressed, and what happens if you press it. That's it. When buttons feel wrong — the confirm dialog that fires twice, the submit that grays out for a beat but still accepts a click, the icon-only control that looks disabled when it isn't — it's almost never a visual regression. It's a state machine that leaked.

The essay walks through examples most engineers will recognize on sight: buttons that show a hover state on touch devices and get stuck; buttons that transition to a loading spinner but remain hit-testable; disabled buttons that offer no explanation for *why* they're disabled; primary buttons that visually dominate a modal so hard that users click them without reading. Each one, Wichary notes, is a case of someone treating the button as decoration for an action rather than as the action's user-facing contract.

Why it matters

Most UI regressions ship not because the CSS is wrong but because nobody wrote down the states. If you asked a mid-level engineer to enumerate every state a submit button can be in, you'd probably hear four: default, hover, active, disabled. The real list is closer to a dozen: default, hover, focus, focus-visible, active/pressed, disabled-because-form-invalid, disabled-because-request-in-flight, loading, success-transient, error-transient, keyboard-focused-while-loading, and the ugly one — the state where the network call succeeded but the response is still in flight to the client. Every one of those needs a distinct visual and a distinct answer to "what does clicking me do right now?" — and most component libraries answer maybe five of them out of the box.

This is where Wichary's framing lands hardest for practitioners. The React/Vue/Svelte ecosystems have spent a decade making components *composable* without making them *stateful in a legible way*. A `

Hacker News 514 pts 249 comments

If you're a button, you have one job

→ read on Hacker News
mproud · Hacker News

How about when users accidentally click too much, or they believe the first click didn’t register?I am still reminded of a keynote where Steve Jobs was demoing how much faster PDF documents would display on the newer macOS. So he had engineers put a button in for him to click that would scroll throu

othmanosx · Hacker News

One job doesn't really fit the button thing because a button has to do many things, only one of which is being clickable.Having feedback when clicked, feedback when hovered. A loading state, a disabled state, a mix of everything. That's also something I found very frustrating. Like if you

CWuestefeld · Hacker News

I want to support the "what about debouncing" argument mentioned elsewhere; the author shouldn't just ignore this.But I also hate the "you had one job" meme and want to argue against its mindless usage. Most of the time, when people do the "you had one job" thing,

mawadev · Hacker News

The worst part about this is the amount of lag you have when taking a photo. On samsung phones, its quick and seamless, on other android phones the IO is so slow, one picture is taken and before you can tap the shoot button again you have to wait until it saved the previously shot photo. Sometimes t

bloak · Hacker News

I used to have a device with a physical button which, when you pressed it, would beep and add 30 seconds to the time. However, sometimes it would beep and not add 30 seconds, and sometimes it would add 30 seconds without beeping, so you always had to squint at the dim display to discover whether it

// share this

// get daily digest

Top 10 dev stories every morning at 8am UTC. AI-curated. Retro terminal HTML email.