Back to Ui Ux Pro Max Skill

States and Variants

cli/assets/skills/design-system/references/states-and-variants.md

2.11.04.7 KB
Original Source

States and Variants

Component state definitions and variant patterns.

Interactive States

State Definitions

StateTriggerVisual Change
defaultNoneBase appearance
hoverMouse overSlight color shift
focusTab/clickFocus ring
activeMouse downDarkest color
disableddisabled attrReduced opacity
loadingAsync actionSpinner + opacity

State Priority

When multiple states apply, priority (highest to lowest):

  1. disabled
  2. loading
  3. active
  4. focus
  5. hover
  6. default

State Transitions

css
/* Standard transition for interactive elements */
.interactive {
  transition-property: color, background-color, border-color, box-shadow;
  transition-duration: var(--duration-fast);
  transition-timing-function: ease-in-out;
}
TransitionDurationEasing
Color changes150msease-in-out
Background150msease-in-out
Transform200msease-out
Opacity150msease
Shadow200msease-out

Focus States

Focus Ring Spec

css
/* Standard focus ring */
.focusable:focus-visible {
  outline: none;
  box-shadow: 0 0 0 var(--ring-offset) var(--color-background),
              0 0 0 calc(var(--ring-offset) + var(--ring-width)) var(--ring-color);
}
PropertyValue
Ring width2px
Ring offset2px
Ring colorprimary (blue-500)
Offset colorbackground

Focus Within

css
/* Container focus when child is focused */
.container:focus-within {
  border-color: var(--color-ring);
}

Disabled States

Visual Treatment

css
.disabled {
  opacity: var(--opacity-disabled); /* 0.5 */
  pointer-events: none;
  cursor: not-allowed;
}
PropertyDisabled Value
Opacity50%
Pointer eventsnone
Cursornot-allowed
Backgroundmuted
Colormuted-foreground

Accessibility

  • Use aria-disabled="true" for semantic disabled
  • Use disabled attribute for form elements
  • Maintain sufficient contrast (3:1 minimum)

Loading States

Spinner Placement

ComponentSpinner Position
ButtonReplace icon or center
InputTrailing position
CardCenter overlay
PageCenter of viewport

Loading Treatment

css
.loading {
  position: relative;
  pointer-events: none;
}

.loading::after {
  content: '';
  /* spinner styles */
}

.loading > * {
  opacity: 0.7;
}

Error States

Visual Indicators

css
.error {
  border-color: var(--color-error);
  color: var(--color-error);
}

.error:focus-visible {
  box-shadow: 0 0 0 2px var(--color-background),
              0 0 0 4px var(--color-error);
}
ElementError Treatment
Input borderred-500
Input focus ringred/20%
Helper textred-600
Iconred-500

Error Messages

  • Position below input
  • Use error color
  • Include icon for accessibility
  • Clear on valid input

Variant Patterns

Color Variants

css
/* Pattern for color variants */
.component {
  --component-bg: var(--color-primary);
  --component-fg: var(--color-primary-foreground);
  background: var(--component-bg);
  color: var(--component-fg);
}

.component.secondary {
  --component-bg: var(--color-secondary);
  --component-fg: var(--color-secondary-foreground);
}

.component.destructive {
  --component-bg: var(--color-destructive);
  --component-fg: var(--color-destructive-foreground);
}

Size Variants

css
/* Pattern for size variants */
.component {
  --component-height: 40px;
  --component-padding: var(--space-4);
  --component-font: var(--font-size-sm);
}

.component.sm {
  --component-height: 32px;
  --component-padding: var(--space-3);
  --component-font: var(--font-size-xs);
}

.component.lg {
  --component-height: 48px;
  --component-padding: var(--space-6);
  --component-font: var(--font-size-base);
}

Accessibility Requirements

Color Contrast

ElementMinimum Ratio
Normal text4.5:1
Large text (18px+)3:1
UI components3:1
Focus indicator3:1

State Indicators

  • Never rely on color alone
  • Use icons, text, or patterns
  • Ensure focus is visible
  • Provide loading announcements

ARIA States

html
<!-- Disabled -->
<button disabled aria-disabled="true">Submit</button>

<!-- Loading -->
<button aria-busy="true" aria-describedby="loading-text">
  <span id="loading-text" class="sr-only">Loading...</span>
</button>

<!-- Error -->
<input aria-invalid="true" aria-describedby="error-msg">
<span id="error-msg" role="alert">Error message</span>