Anticode Open builder

UI component states: the checklist every interactive element needs

Every interactive component needs more than its resting look. At minimum: default, hover, keyboard focus, pressed and disabled, and for many components also loading, selected, error and visited. Design them together as a set, with one rule for what each state changes, so a visitor learns the pattern once and recognises it on every button, link and field.

Updated · By the Anticode team

Why states get missed

Mock-ups show components at rest. Hover is usually added during build, focus often never, and disabled or loading states appear only when a developer meets the case and improvises. The result is a site where one button darkens on hover, another fades, a third does nothing, and keyboard users can't see where they are. Designing states as a deliberate set, at the same time as the resting style, prevents that.

The interactive states checklist

States by component
StateWhat it tells the visitorApplies to
DefaultThis can be usedEverything interactive
HoverThe pointer is over something you can useButtons, links, cards that link, rows
FocusThis is where the keyboard isEverything that can receive focus
Active (pressed)Your press registeredButtons, links, toggles
DisabledThis exists but can't be used yetButtons, fields, options
LoadingYour action is being processedButtons that send, fetch or save
Selected or currentThis is the chosen option or the page you're onTabs, navigation, time slots, filters
ErrorThis needs fixingFields, groups of options
VisitedYou've been hereText links in long content

Designing hover, focus, active and disabled as a set

Pick one change per state and apply it everywhere. A workable set for a site with one action colour:

  1. Hover: a clear change of fill or underline. A filled button gets a slightly darker or lighter fill; a text link gains or thickens its underline; a card's title takes the action colour. Avoid fading to lower opacity, which reads as disabled.
  2. Focus: a solid outline, offset from the element by two or three pixels, in a colour with at least 3:1 contrast against the background. Use :focus-visible so it shows for keyboard users and not on every mouse click; MDN's focus-visible reference explains the browser's heuristics. Never remove focus without replacing it.
  3. Active: a brief, small response, such as a slight press inwards or a darker fill, so the press feels physical.
  4. Disabled: lower contrast and no pointer change, but still readable. Better still, explain why something is unavailable, or leave the button enabled and say what's missing when it's pressed.
  5. Loading: keep the button's width, swap the label for a short phrase such as "Sending", and prevent a second press.

Hover and focus should look different. If they're identical, a keyboard user who also moves the mouse can't tell which element will respond to Enter. Focus state design and hover effects for websites go deeper on each.

Accessibility rules for states

  • Focus must be visible. WCAG's Focus Visible criterion, at level AA, requires a mode where keyboard focus can be seen.
  • State changes need contrast. WCAG's Non-text Contrast asks for 3:1 for the visual cues that show a component's state, such as selected or focused. Hover itself doesn't need to reach 3:1, but it mustn't reduce contrast below what the component needs.
  • Not colour alone. A selected tab that differs only by hue fails people who can't see that hue. Add weight, an underline, a fill or a check mark.
  • Expose state in code. aria-current="page" for the current page, aria-pressed for toggle buttons, aria-invalid for fields in error, the native disabled attribute for unavailable controls.
  • Touch has no hover. Anything revealed on hover needs another route on phones and tablets.

Motion between states

Short transitions make state changes easier to follow, as long as they're quick: around 100 to 200 milliseconds for colour and fill. Use a purposeful curve rather than the browser's default ease, and turn transitions off for visitors who ask their device for reduced motion. UI animation duration gives fuller timings.

Component states in Anticode

Anticode's design systems define focus and hover states as part of each system. Every page shows a visible keyboard focus ring in the action colour, offset from the element, and since 23 October 2026 the design gate blocks publishing any page that has no focus styles at all. Booking time slots have a distinct selected state and their own focus ring.

The Critic checks two common state habits on every build: hover states that do nothing but fade the opacity, and cards that all lift upwards on hover. It also flags transitions that use the default ease curve, and every design system turns animation and transitions off under reduced-motion settings.

Questions people ask

What states does a button need?

Default, hover, focus, pressed and disabled at minimum, and a loading state if pressing it sends or saves something.

What's the difference between focus and focus-visible?

:focus matches any focused element; :focus-visible matches only when the browser judges a visible indicator is needed, such as during keyboard navigation.

Should disabled buttons be greyed out?

They're usually shown with lower contrast, but keep the label readable and, where possible, explain what's needed to enable the action.

Sources

  1. :focus-visible, MDN Web Docs, checked
  2. Understanding SC 2.4.7: Focus Visible, W3C, checked
  3. Understanding SC 1.4.11: Non-text Contrast, W3C, checked