Skip to main content

Interaction States

Why interaction states matter

Every interactive element must communicate its current state to the user — visually and programmatically. DIR Web Modernization standards and WCAG 2.2 SC 1.4.11 (Non-text Contrast) require a ≥ 3:1 contrast ratio between an element's default state and its interactive states.

State definitions

State Trigger Visual treatment
Default No interaction Base component appearance
Hover Pointer over element Slight background shift or underline; cursor changes to pointer
Focus Keyboard tab or programmatic focus 2px solid outline using --txds-focus-color with --txds-focus-offset gap
Active / Pressed Mouse-down or Enter key Darkened background, slight scale down (transform: scale(0.98))
Disabled disabled or aria-disabled="true" Reduced opacity (0.4), cursor: not-allowed, no pointer events
Selected / Checked Radio, checkbox, toggle in "on" state Primary-color fill or border
Error / Invalid Failed validation Red border, associated error message via aria-describedby

Component state matrix

The table below shows which states each component supports. "—" means the state is not applicable.

Component Hover Focus Active Disabled Selected Error
Button
Text input
Checkbox
Radio
Select
Link
Accordion
Card
Chip
Pagination
Modal close
Tab

Token-driven states

All interactive states use shared design tokens so they stay consistent across components:

:root {
  /* Focus ring */
  --txds-focus-color: #2563eb;       /* Blue-600 */
  --txds-focus-width: 2px;
  --txds-focus-offset: 2px;

  /* Disabled */
  --txds-disabled-opacity: 0.4;
}

/* Global focus ring applied to all focusable elements */
*:focus-visible {
  outline: var(--txds-focus-width) solid var(--txds-focus-color);
  outline-offset: var(--txds-focus-offset);
}

Implementation checklist

  • [ ] Every <button type="button">, <a>, and <input> has visible hover, focus, and active states.
  • [ ] Focus indicators meet 3:1 contrast against adjacent colors (WCAG 2.2 SC 1.4.11).
  • [ ] Disabled elements use opacity + pointer-events: none and aria-disabled="true".
  • [ ] No state relies solely on color change — pair with border, underline, or icon change.
  • [ ] Interactive state contrast verified with browser DevTools forced-state tool.
  • [ ] Keyboard-only testing confirms no "focus trap" except inside open modals.

Testing states in the browser

Use Chrome DevTools to force element states:

  1. Right-click the element → Inspect.
  2. In the Styles panel, click :hov to toggle :hover, :focus, :active, etc.
  3. Verify contrast with the built-in Contrast ratio picker in the color swatch.