R3.15.3unresponsive early controlsdesign

Showing unusable controls early creates an unresponsive impression

Aliases: dead button · hydration gap · premature affordance · false interactivity

What it is

A control painted in its final, clickable look before events are attached will be used as a real button. A tap with no response is retried, read as broken, abandoned, or — when script finally arrives — flushed as a double submit. Showing unusable controls early creates an unresponsive impression, not a faster first screen. Skeletons, disabled states, and an explicit "not yet" at least admit the gap; a high-fidelity fake control disguises the gap as a fault.

This is how the gap is presented, and how that presentation is read as damage. That two moments exist is the premise; this is what you paint inside the gap.

Why it happens

A clickable look is a promise: size, contrast, button shape, and a finger will press. If no listener is present, the system usually swallows the tap, or moves focus without firing an action. With no change inside about 100 ms, people explain it as "broken", not as "still loading". Repeated taps then fire together the instant hydration finishes: two form posts, two cart adds. The more finished it looks, the stronger the promise, and the worse the breakage when it is broken. Grey disabled, a pulsing skeleton, a progress mark downgrade the promise to "not ready", so the same wait is read as in progress rather than as a fault.

This is not the same claim as "perceived waits can be shortened". Painting the unusable as usable makes the wait feel like failure; painting unreadiness as unreadiness makes the wait feel like a wait. Early finished paint inserts a false interactive moment between the two clocks.

Where it stops holding

Static links and native <a> / <button> work when the HTML arrives, without framework hydration — their final look is real readiness, not a disguise. After prefetch, a gap too short to tap into never forms the broken impression; as soon as a slow network makes the gap tappable, the rule returns. Game and canvas buttons have no DOM disabled state and need their own "not ready" look. A read-only preview (article body first, comment field later) that paints the comment field as a working input you cannot type into is the same false affordance; the body itself is not a control, so painting it first is fine. Assistive technology may already focus the visual button in the gap; unresponsiveness is then spoken as "selected" with no action — the same damage.

Applying it

  • Primary actions, submit, add-to-cart, open-menu: until listeners are ready, use a skeleton, disabled, or an unfocusable placeholder — not the final button look.
  • Emit real HTML early for links and buttons that work natively, so they are clickable before hydration, rather than painting a fake button and swapping it.
  • If clicks happened in the gap, coalesce them into one when hydration finishes and give feedback; do not double-submit.
  • How to check: under CPU throttle, tap the primary button as soon as it appears. Record time from first tap to first visible response, and whether a double submit occurred. If it looks like a button and there is neither response nor a busy state, it was shown too early. Compare a disabled/skeleton treatment: is the same gap still described as "broken"?

Related

  • Same group: R3.15.1 Visible and operable are two different moments · R3.15.2 Metrics come from the high percentiles of real users, not the mean
  • Nearby: R3.04 Performance Budgets · I2.07 Perceived Performance
  • Search terms: unresponsive early controls · hydration gap · dead button · INP

Cards in the same group

Quick Actions

Share

Share this page

ios_share

https://hci.top/en/handbook/R3.15.3