Skip to content
ExamsLibraryFor agentsConnect your agent

A button has eight states

beginner·8 min·Markdown for agents

What this lesson teaches

Give every control its hover, pressed, focus, loading, done, error and disabled states, keep them from shifting the layout, and run the polish pass that makes a component feel finished.

  1. 1The eight, in one line each
  2. 2Hover is not lift and shadow
  3. 3Pressed, by product
  4. 4Disabled, layered right
  5. 5The polish pass
  6. 6Personality comes last, and sparingly

Press the Save button. Then walk through the picker, one state at a time.

Resting: a clear label that starts with a verb. Press it to play the real sequence.

One button, eight looks. The width never changes, so nothing around it moves.

An agent will happily give you the resting button and a hover color. The other six states are where a button earns trust: it answers your press, tells you it is working, and confirms it worked, all in the same spot.

The eight, in one line each

  • Rest. A label that starts with a verb: "Save changes".
  • Hover. One step of background. Only on devices that can hover. This is the .
  • Pressed. scale(0.97) on :active, through a ~150ms transition. Never below 0.95.
  • Focus. A visible ring for keyboard users, through . More in the keyboard lesson.
  • Loading. The label says what is happening ("Saving…"), clicks are ignored, the width holds.
  • Done. It confirms on itself ("Saved"), holds a beat, returns to rest.
  • Error. It says what did not happen; the details sit beside the form.
  • Disabled. Faded and inert, with the reason written next to it.
The loading label and the done label live in the same box, stacked. Swapping them never resizes the button.

Hover is not lift and shadow

The reflex hover is "lift the card 4px and add a big shadow". It is dated, and it is one of the tells of generated UI. Hover over both cards:

Lift 4px and a big shadow
Atlas rebrand12 files · Updated 2h ago
1px and one step of tint
Atlas rebrand12 files · Updated 2h ago

Hover over each card with a mouse. The left one jumps at you; the right one is felt more than seen, which is what a card you pass fifty times a day should do.

Real hover with a mouse; the switch shows it on a touch screen.

Quieter patterns read as more considered:

ElementHover
Rows, list items, table cellsA background shift, about rgba(0,0,0,0.04), over 120ms
CardstranslateY(-1px) and one step of tint
InputsThe border gets one step darker
Icon buttonsThe icon inside scales to 1.05, not the button

A 1px lift is felt more than seen. 4px looks bouncy.

Two rules keep hover honest. First, gate it: wrap hover styles in @media (hover: hover) and (pointer: fine). A phone fires :hover on tap and leaves it stuck, which looks broken. Second, never change layout on hover: no margin, padding, width or font weight. Animate only transform, opacity, background-color, border-color or box-shadow, so the neighbors stay put.

Pressed, by product

How much a button squishes depends on who presses it. A consumer app can press to scale(0.96); it reads as delight. A tool someone uses all day stays subtler, scale(0.98) or just a background change, because a springy button pressed four hundred times a day gets tiring.

Disabled, layered right

opacity: 0.5 and cursor: not-allowed is fine for a simple button. On a text input, give it an explicit disabled background and muted text instead; a flat opacity on a complex element looks washed out. And the classic mistake: a submit button disabled until the form is valid tells the user nothing about why. Let them press it and show the errors.

The polish pass

Once the component works, run one pass over it. Each item is invisible on its own; together they are the difference between "works" and "finished".

  1. Hold the weight

    Never change font weight on hover or selection; bold text is wider and reflows the row. Signal with color.
  2. Tabular numbers

    font-variant-numeric: tabular-nums on anything that counts, so digits stop jiggling.
  3. No layout shift

    Skeletons, images and placeholders carry the loaded size or an aspect-ratio.
  4. States that stay put

    Hover transitions only the properties that change, ~150ms ease-out. Focus rings stay neutral and never vanish.
  5. One z-index scale

    Dropdown 100, modal 200, tooltip 300, toast 400, or isolation: isolate. Never z-index: 9999.
  6. Hit areas and optics

    Targets of 44px on touch, grown with a pseudo-element. Nudge a play triangle 1 to 2px toward its point so it looks centred.
  7. Decoration is inert

    pointer-events: none on glows and ornaments, so they never swallow a click.

Polish applied to the wrong structure gets thrown away with it. If the hierarchy or spacing is wrong, fix that first.

Personality comes last, and sparingly

Once every state is right, a product can earn a little character in how it responds. Personality lives in interactions, not in static screens: a success message that names what happened ("Sent to 47 recipients" instead of "Success!"), a loading line that informs ("Fetching your last 30 days…"), a Delete that answers 100ms slower than Save because deliberation suits destruction.

Easter eggs belong where people are curious (a 404 page, Settings, a long press on the logo), never in the middle of signup or payment. And restraint wins: one well-placed surprise feels alive; ten feel exhausting. In a tool analysts use all day, skip it.

Every state of a control· for your agent
Give this button all of its states: rest, hover, pressed, focus, loading, done, error, disabled.
- Hover only inside @media (hover: hover) and (pointer: fine); one step of background, no lift, no layout change.
- Pressed: scale(0.97) on :active, 150ms ease-out.
- Focus: :focus-visible ring, 2px, neutral color, 2px offset.
- Loading: label "Saving…", ignore repeat clicks, fixed width; the labels are stacked layers that crossfade.
- Done: "Saved" on the button for ~1.5s, then back to rest. Error: "Not saved", details beside the form.
Then run a polish pass: constant font weight, tabular-nums on numbers, no layout shift, no z-index above the scale.

Quick check

A tab bar makes the selected tab bold. What goes wrong, and what is the fix?

What this lesson builds on and leads to, across every course.

  • Routing the job
  • Your first review
  • Every list has four states