tailthemes
all-access
notes
6 min

The screen makes promises

A person gripping a door handle on a tall plain slab and leaning back to pull it; the slab has no opening, and the handle is the one highlighted element.
A person gripping a door handle on a tall plain slab and leaning back to pull it; the slab has no opening, and the handle is the one highlighted element.

A false affordance is a cue that promises an interaction the screen does not deliver: blue underlined text that is not a link, a raised card that opens nothing, a chevron with nothing behind it. Treat every visual cue as an API contract. Customers read your styling as documentation, and when one promise breaks they stop trusting the rest.

What is a false affordance?

The term is older than flat design. William Gaver's paper Technology Affordances (CHI '91) sorted interface cues by asking two questions: can the thing be done, and does anything on the surface say it can?

  • Perceptible: the action exists and a cue says so.
  • Hidden: the action exists and nothing points at it.
  • False: a cue points at an action that does not exist.

Gaver's own wording for the third: "a false affordance exists upon which people may mistakenly try to act." Don Norman later named the cue itself in his 2008 interactions column Signifiers, not affordances: "I call any physically perceivable cue a signifier, whether it is incidental or deliberate."

In software terms, the signifier is the documentation and the click handler is the implementation. A false affordance is documentation for an endpoint nobody built. The hidden case, a feature that works with no cue pointing at it, is its own failure with its own fixes; this note is about the cue that lies.

Which cues make promises, and how do they break?

Every common cue carries one specific promise. The right-hand column is where our own contracts name the rule, so you can see the promise written down as a rule an agent reads.

CueWhat the customer readsHow the promise breaksWhere we wrote the rule
Filled buttonpressing it does somethinga styled div with no handler, or an enabled-looking button for a feature that is not open/colour-pass §3: --primary is for the dominant action
Underline in link colourthis goes somewhereemphasis dressed as a link/colour-pass §3: links get --link, not a borrowed --primary
Shadow and hover lift on a cardthe card opensa static card styled like a clickable onethemes/CONTRACT.md: default cards are flat; a surface that lifts is interactive
Pointer cursorthis element actscursor-pointer on a whole card where one button works/motion-pass: pointer only on things that act
Keycap such as ⌘Kthat key does that thingthe shortcut drawn, the handler never written/interaction-pass §4: a displayed affordance is a promise
Chevron or caretmore is behind thisa decorative arrow on a row that expands nothing/interaction-pass §4, the same general rule

What happens when the customer clicks and nothing happens?

Picture a pricing page where the plan names are bold, blue and underlined. The team styled them to stand out. A customer clicks "Pro" and nothing happens, so they click again, harder.

The second click is the cost nobody sees. The customer is now unsure what else on the page works: is "Start trial" a real button, does the comparison table expand, are the FAQ questions links? Every cue on the page now costs a test click before it earns trust.

A person pressing the middle row of a small screen, which carries an underline and is the highlighted element; small arcs by the hand show a second press, and the screen does not change.
The underline promised a link. The second press is the customer testing the promise, and the screen answers with nothing.

The nearest measurement is Nielsen Norman Group's 2017 eyetracking study of weak clickability signifiers. Across 71 users and nine pages built in two versions, the versions with faint cues took 22% more time and drew 25% more fixations. It measured the opposite failure, links that worked but did not look it. It still prices the thing that matters here: when cues cannot be relied on, people look longer and wider before they act.

So here is the argument, stated as an argument rather than a number.

Broken features get bug reports. Broken promises get silent churn.

A click on a dead element throws no error and files no ticket. The customer files a judgement about the product instead.

Session-replay tools see the trace of it. Microsoft Clarity, for one, marks a dead click when an element gets no feedback, and a rage click when someone clicks the same spot again and again. That report is the cheapest place to find your own false affordances.

Why treat a visual cue like an API contract?

Engineers already hold this discipline for APIs. If the docs say an endpoint returns JSON, it returns JSON, and changing that is a breaking change that gets versioned and announced. A visual cue is the same kind of promise, published to everyone who looks at the screen, and it deserves the same review.

One question in design review covers it: what does this design imply, not only what does it support? "Support" is what the handlers do. "Imply" is what the styling says they do. Your bug list is the difference between the two.

Three tiles in a row; the first two each connect by a short line to a box below them, and the third, highlighted, has nothing beneath it.
Cues on top, handlers below. Two promises are wired to something; the third implies an action nothing supports, and that gap is the false affordance.

Diff your cues against your handlers

Open your pricing page or your busiest screen and list everything that wears a promise: link colour, underline, fill, shadow, chevron, pointer cursor, keycap. Press each one. Anything that does nothing is a false affordance, and the fix is to build the behaviour or remove the cue. In code, the quick version is a search for cursor-pointer, underline and your link colour class on anything that is not an a or a button.

Does UI an agent builds make more of these promises?

We have no count that says it does. The mechanism is easy to see, though. Code is cheap now: "make the plan names stand out" is one sentence to a coding agent, and the loudest tokens in reach are the link colour and the primary colour. Nothing in that request says those colours are promises.

So we wrote the promises down where an agent reads them before it styles anything, in the skills and the contract named in the table above. The pricing table in Grove shows what that produces (themes/grove/src/components/pricing-table.tsx). Each plan name is an h3 in the foreground ink, not the link colour; the cards are flat with a border; the one filled button belongs to the featured plan; and the monthly and yearly switch carries aria-pressed, so its state is announced as well as drawn.

Grove ships the rule along with the page: its own check-quality skill greps for text-primary underline, a link wearing the action colour, beside the other role mix-ups it refuses. An agent editing the theme later meets the same rule we did.

Do the old cues still count?

Conventions drift. Flat design removed most raised cues, underlines are no longer the only link signal, and a whole card that opens is a normal pattern now. The test is not whether a cue follows the 2010 rules. It is whether your customers read it correctly, which you find out by watching them, not by citing a convention.

Three limits on what this note argues. We have no measure of churn caused by false affordances; "silent churn" is the argument, not a statistic. The NN/g numbers are about cues that were too weak, not cues that lied. And our own rule is enforced by review rather than by machine: a check-affordance.ts script was considered in our 2026-08-22 review of these skills and rejected as brittle, because type-ahead and shared handlers have no literal key to match.

share this

Get the next one

Posts go up at most weekly, and only with data behind them. New themes ship in the same mail.

  • we confirm first
  • one-click out
  • no tracking