Default, hover, pressed, disabled, and loading states all have to exist
Aliases: button states · control states · rest hover active disabled
What it is
A button needs a complete state machine: default (rest), hover, pressed (active), disabled, and loading. Completeness means every interaction phase that actually occurs has a matching look and behavior—not that a file contains a default frame and a disabled frame. Without hover, pointer users cannot tell the object is clickable. Without pressed, it is unclear whether contact was sampled. Without loading, the control stays at rest after submit and looks as if nothing happened. The five states are the trigger’s minimum life cycle, not a skin list.
Why it happens
A button’s job is to send an intent and block a second intent until a result returns. Each state answers a life-cycle question: default, “this can be hit”; hover, “the pointer is on it”; pressed, “contact was sampled”; disabled, “it cannot be hit now, and it is not broken”; loading, “the last intent is already in flight.” If any state is missing, people guess the current phase from a neighbor. Typical misreads: treating disabled as loading and waiting, treating loading as default and clicking again, treating a flat unhovered block as decoration. When the machine is incomplete, the failure happens before any result component appears—people are already lost on the trigger.
Studying it
Audit coverage rather than satisfaction. List pointer-enter, press, release, keyboard activation, no-permission, and in-flight request; check that each lands on a definite one of the five states. Then run a mutilated control: drop hover or drop loading on the same “change email and save” task.
Independent variables: which state is missing, input channel (mouse / touch / keyboard). Dependent variables: clicks on disabled, double submits, decoration-versus-button confusions, time to finish.
Touch has no hover phase. Mark hover as channel-not-applicable, not as missing. Counting absent hover on a phone as a defect inflates incompleteness.
Where it stops holding
A touch-only product can omit hover; pressed, disabled, and loading still have to exist. Keyboard focus is not one of the five, yet it still needs a visible focus indicator or keyboard users fall out of an otherwise complete mouse machine. Instant local actions (switching a tab in one frame) need not enter loading; a spinner would only flash. On a toggle, on/off is a value, not one of these five; do not let pressed stand in for selected.
Applying it
- For every button component, specify look and behavior of the five states, and mark which state is inapplicable on the current channel (no hover on touch).
- Move request-start into loading and request-end back to default or disabled in the same transition; do not leave that cutover in the API layer alone.
- Keyboard activation must be able to enter pressed and loading, not only the mouse.
- Verify with mouse, touch, and keyboard on “idle → in-flight → clickable again after failure” and on a no-permission disabled case. If any channel looks at rest while a request is out, or looks clickable while disabled, the five states are incomplete.
Related
- Within the group: E1.02.2 State-to-state visual difference must exceed noise · E1.02.3 A missing pressed state causes repeated clicks
- Adjacent: E1.11 Button state completeness across contexts · D1.05 Hover feedback · D1.06 Pressed state · D1.07 Disabled state
- Search terms:
button states·control state machine·hover pressed disabled loading