Design Systems

States & Variants

Every interactive component has required states that must be explicitly designed. Missing states create broken experiences.

#states#variants#hover#focus#disabled#loading#error#success#active

What is it?

States and variants are the different visual representations of a component based on its current condition or context. States are dynamic (hover, focus, loading, disabled — they change during use). Variants are static alternatives (primary/secondary, size small/medium/large — they are chosen at design time). Every component that can change must have all its states explicitly designed.

Why it matters

Missing states cause broken-feeling products. A button with no hover state feels static and unresponsive. An input with no error state provides no feedback on failure. A disabled button with no disabled styling looks like a broken regular button. States are not optional — they are part of the component specification.

Best Practices

  • Every interactive component must have: default, hover, focus, active, disabled states.
  • Form inputs must have: empty, focused, filled, error, success, disabled states.
  • Async components (buttons that trigger requests) must have a loading state.
  • Focus state must be visible — never remove outline without replacing with an equivalent visible indicator.
  • Disabled states: slightly reduced opacity + not-allowed cursor. Never remove disabled styling to "simplify" the design.
  • Error states: red border + error icon + error message below. All three elements together.
  • Loading state: spinner inside the button, text changes to "Saving..." or "Loading..."
  • Success state: checkmark + success color. Brief (auto-dismisses after 2 seconds).
  • Skeleton states for content components (cards, lists) that load asynchronously.
  • Empty states for list/collection components when there is no data.

Common Mistakes

  • Missing focus states — inaccessible and a common CSS reset issue.
  • No loading state on buttons that trigger async operations.
  • No disabled styling — disabled buttons look like broken buttons.
  • Error state that only changes text color — insufficient for colorblind users.
  • Hover states that are too subtle — users can't tell they've hovered.
  • No skeleton states — blank loading areas feel broken.
  • Designing only the default state and leaving states to developer interpretation.

Checklist

Research & Theory

WCAG 2.4.11 — Focus Appearance (Level AA)

WCAG 2.2 introduced a requirement for focus indicators to meet minimum size and contrast requirements — not just to exist.

Why it's relevant

Focus states are a legal accessibility requirement, not just a best practice. Design them to be visible and to pass WCAG 2.2 AA.

Real-World Examples

Figma

Figma's own components in their UI are the best reference for state design. Every button, input, and interactive element has all states implemented and visible.

Linear

Every interactive element in Linear has a clear hover, focus, and active state. The design system is consistent enough that new developers can intuit the pattern.

GitHub

GitHub's Primer system documents all states for every component. Focus states are highly visible (blue ring). Disabled states are clear. Loading states use skeleton screens.