Skip to main content
Make interactions feel fast. Use optimistic UI—update immediately, sync later.

The Eight Interactive States

Every interactive element needs these states designed:
The common miss: Designing hover without focus, or vice versa. They’re different. Keyboard users never see hover states.

Focus Rings: Do Them Right

Never outline: none without replacement. It’s an accessibility violation. Instead, use :focus-visible to show focus only for keyboard users:
Focus ring design:
  • High contrast (3:1 minimum against adjacent colors)
  • 2-3px thick
  • Offset from element (not inside it)
  • Consistent across all interactive elements

Form Design: The Non-Obvious

Placeholders aren’t labels—they disappear on input. Always use visible <label> elements.
Validate on blur, not on every keystroke (exception: password strength). Place errors below fields with aria-describedby connecting them.

Loading States

Optimistic Updates

Show success immediately, rollback on failure. Use for: Low-stakes actions (likes, follows) Avoid for: Payments or destructive actions

Skeleton Screens

Skeleton screens > spinners—they preview content shape and feel faster than generic spinners.

Modals: The Inert Approach

Focus trapping in modals used to require complex JavaScript. Now use the inert attribute:
Or use the native <dialog> element:

The Popover API

For tooltips, dropdowns, and non-modal overlays, use native popovers:
Benefits: Light-dismiss (click outside closes), proper stacking, no z-index wars, accessible by default.

Destructive Actions: Undo > Confirm

Undo is better than confirmation dialogs—users click through confirmations mindlessly.
Use confirmation only for:
  • Truly irreversible actions (account deletion)
  • High-cost actions
  • Batch operations

Keyboard Navigation Patterns

Roving Tabindex

For component groups (tabs, menu items, radio groups), one item is tabbable; arrow keys move within:
Arrow keys move tabindex="0" between items. Tab moves to the next component entirely. Provide skip links (<a href="#main-content">Skip to main content</a>) for keyboard users to jump past navigation. Hide off-screen, show on focus.

Gesture Discoverability

Swipe-to-delete and similar gestures are invisible. Hint at their existence:
  • Partially reveal: Show delete button peeking from edge
  • Onboarding: Coach marks on first use
  • Alternative: Always provide a visible fallback (menu with “Delete”)
Don’t rely on gestures as the only way to perform actions.

Guidelines

DO

  • Use progressive disclosure—start simple, reveal sophistication through interaction
  • Design empty states that teach the interface, not just say “nothing here”
  • Make every interactive surface feel intentional and responsive
  • Use optimistic UI for low-stakes actions
  • Provide keyboard alternatives for all mouse interactions
  • Use skeleton screens instead of generic spinners

DON’T

  • Repeat the same information—redundant headers, intros that restate the heading
  • Make every button primary—use ghost buttons, text links, secondary styles; hierarchy matters
  • Remove focus indicators without alternatives
  • Use placeholder text as labels
  • Create touch targets <44x44px
  • Use generic error messages
  • Build custom controls without ARIA/keyboard support