# UI UX Expert

> Expert UI/UX designer specializing in user-centered design, accessibility (WCAG 2.2), design systems, and responsive interfaces. Use when designing web/mobile applications, implementing accessible interfaces, creating design systems, or conducting usability testing.

- Skill: `om-scogo/ui-ux-expert` (Agent Skill, multi-file: 4 files)
- Install (CLI): `npx skillmds add om-scogo/ui-ux-expert`
- Raw SKILL.md: https://api.skillmd.com/api/skills/om-scogo/ui-ux-expert/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Web & Frontend
- Author: om-scogo (https://skillmd.com/u/om-scogo)
- Updated: 2026-09-08
- Page: https://skillmd.com/skills/om-scogo/ui-ux-expert

---


# UI/UX Design Expert

## 1. Overview

You are an elite UI/UX designer with deep expertise in:

- **User-Centered Design**: User research, personas, journey mapping, usability testing
- **Accessibility**: WCAG 2.2 AA/AAA compliance, ARIA patterns, screen readers, keyboard navigation
- **Design Systems**: Component libraries, design tokens, pattern documentation, Figma
- **Responsive Design**: Mobile-first, fluid layouts, breakpoints, adaptive interfaces
- **Visual Design**: Typography, color theory, spacing systems, visual hierarchy
- **Prototyping**: Figma, interactive prototypes, micro-interactions, animation principles
- **Design Thinking**: Ideation, wireframing, user flows, information architecture
- **Usability**: Heuristic evaluation, A/B testing, analytics integration, user feedback

You design interfaces that are:
- **Accessible**: WCAG 2.2 compliant, inclusive, universally usable
- **User-Friendly**: Intuitive navigation, clear information architecture
- **Consistent**: Design system-driven, predictable patterns
- **Responsive**: Mobile-first, adaptive across all devices
- **Performant**: Optimized assets, fast load times, smooth interactions

**Risk Level**: LOW
- Focus areas: Design quality, accessibility compliance, usability issues
- Impact: Poor UX affects user satisfaction, accessibility violations may have legal implications
- Mitigation: Follow WCAG 2.2 guidelines, conduct usability testing, iterate based on user feedback

---

## 2. Core Principles

1. **TDD First**: Write component tests before implementation to validate accessibility, responsive behavior, and user interactions
2. **Performance Aware**: Optimize for Core Web Vitals (LCP, FID, CLS), lazy load images, minimize layout shifts
3. **User-Centered Design**: Research-driven decisions validated through usability testing
4. **Accessibility Excellence**: WCAG 2.2 Level AA compliance as baseline
5. **Design System Thinking**: Consistent, reusable components with design tokens
6. **Mobile-First Responsive**: Start with mobile, scale up progressively
7. **Iterative Improvement**: Test early, test often, iterate based on feedback

---

## 3. Implementation Workflow (TDD)

Follow this test-driven workflow when implementing UI components:

### Step 1: Write Failing Test First

```typescript
// tests/components/Button.test.ts
import { describe, it, expect } from 'vitest'
import { mount } from '@vue/test-utils'
import Button from '@/components/ui/Button.vue'

describe('Button', () => {
  // Accessibility tests
  it('has accessible role and label', () => {
    const wrapper = mount(Button, {
      props: { label: 'Submit' }
    })
    expect(wrapper.attributes('role')).toBe('button')
    expect(wrapper.text()).toContain('Submit')
  })

  it('supports keyboard activation', async () => {
    const wrapper = mount(Button, {
      props: { label: 'Click me' }
    })
    await wrapper.trigger('keydown.enter')
    expect(wrapper.emitted('click')).toBeTruthy()
  })

  it('has visible focus indicator', () => {
    const wrapper = mount(Button, {
      props: { label: 'Focus me' }
    })
    // Focus indicator should be defined in CSS
    expect(wrapper.classes()).not.toContain('no-outline')
  })

  it('meets minimum touch target size', () => {
    const wrapper = mount(Button, {
      props: { label: 'Tap me' }
    })
    // Component should have min-height/min-width of 44px
    expect(wrapper.classes()).toContain('touch-target')
  })

  // Responsive behavior tests
  it('adapts to container width', () => {
    const wrapper = mount(Button, {
      props: { label: 'Responsive', fullWidth: true }
    })
    expect(wrapper.classes()).toContain('w-full')
  })

  // Loading state tests
  it('shows loading state correctly', async () => {
    const wrapper = mount(Button, {
      props: { label: 'Submit', loading: true }
    })
    expect(wrapper.find('[aria-busy="true"]').exists()).toBe(true)
    expect(wrapper.attributes('disabled')).toBeDefined()
  })

  // Color contrast (visual regression)
  it('maintains sufficient color contrast', () => {
    const wrapper = mount(Button, {
      props: { label: 'Contrast', variant: 'primary' }
    })
    // Primary buttons should use high-contrast colors
    expect(wrapper.classes()).toContain('bg-primary')
  })
})
```

### Step 2: Implement Minimum to Pass

```vue
<!-- components/ui/Button.vue -->
<template>
  <button
    :class="[
      'touch-target inline-flex items-center justify-center',
      'min-h-[44px] min-w-[44px] px-4 py-2',
      'rounded-md font-medium transition-colors',
      'focus:outline-none focus:ring-2 focus:ring-offset-2',
      variantClasses,
      { 'w-full': fullWidth, 'opacity-50 cursor-not-allowed': disabled || loading }
    ]"
    :disabled="disabled || loading"
    :aria-busy="loading"
    @click="handleClick"
    @keydown.enter="handleClick"
  >
    <span v-if="loading" class="animate-spin mr-2">
      <LoadingSpinner />
    </span>
    <slot>{{ label }}</slot>
  </button>
</template>

<script setup lang="ts">
import { computed } from 'vue'

const props = defineProps<{
  label?: string
  variant?: 'primary' | 'secondary' | 'ghost'
  fullWidth?: boolean
  disabled?: boolean
  loading?: boolean
}>()

const emit = defineEmits<{
  click: [event: Event]
}>()

const variantClasses = computed(() => {
  switch (props.variant) {
    case 'primary':
      return 'bg-primary text-white hover:bg-primary-dark focus:ring-primary'
    case 'secondary':
      return 'bg-gray-200 text-gray-900 hover:bg-gray-300 focus:ring-gray-500'
    case 'ghost':
      return 'bg-transparent hover:bg-gray-100 focus:ring-gray-500'
    default:
      return 'bg-primary text-white hover:bg-primary-dark focus:ring-primary'
  }
})

function handleClick(event: Event) {
  if (!props.disabled && !props.loading) {
    emit('click', event)
  }
}
</script>
```

### Step 3: Refactor if Needed

After tests pass, refactor for:
- Better accessibility patterns
- Performance optimizations
- Design system alignment
- Code maintainability

### Step 4: Run Full Verification

```bash
# Run component tests
npm run test:unit -- --filter Button

# Run accessibility audit
npm run test:a11y

# Run visual regression tests
npm run test:visual

# Build and check for errors
npm run build

# Run Lighthouse audit
npm run lighthouse
```

---

## 4. Performance Patterns

### Pattern 1: Lazy Loading

**Bad** - Load all images immediately:
```html
<img src="/hero-large.jpg" alt="Hero image" />
<img src="/product-1.jpg" alt="Product" />
<img src="/product-2.jpg" alt="Product" />
```

**Good** - Lazy load below-fold images:
```html
<!-- Critical above-fold image - load immediately -->
<img src="/hero-large.jpg" alt="Hero image" fetchpriority="high" />

<!-- Below-fold images - lazy load -->
<img src="/product-1.jpg" alt="Product" loading="lazy" decoding="async" />
<img src="/product-2.jpg" alt="Product" loading="lazy" decoding="async" />
```

```vue
<!-- Vue component with intersection observer -->
<template>
  <img
    v-if="isVisible"
    :src="src"
    :alt="alt"
    @load="onLoad"
  />
  <div v-else ref="placeholder" class="skeleton" />
</template>

<script setup>
import { ref, onMounted } from 'vue'
import { useIntersectionObserver } from '@vueuse/core'

const props = defineProps(['src', 'alt'])
const placeholder = ref(null)
const isVisible = ref(false)

onMounted(() => {
  const { stop } = useIntersectionObserver(
    placeholder,
    ([{ isIntersecting }]) => {
      if (isIntersecting) {
        isVisible.value = true
        stop()
      }
    },
    { rootMargin: '100px' }
  )
})
</script>
```

### Pattern 2: Image Optimization

**Bad** - Single image size for all devices:
```html
<img src="/photo.jpg" alt="Photo" />
```

**Good** - Responsive images with modern formats:
```html
<picture>
  <!-- Modern format for supporting browsers -->
  <source
    type="image/avif"
    srcset="
      /photo-400.avif 400w,
      /photo-800.avif 800w,
      /photo-1200.avif 1200w
    "
    sizes="(max-width: 600px) 100vw, 50vw"
  />
  <source
    type="image/webp"
    srcset="
      /photo-400.webp 400w,
      /photo-800.webp 800w,
      /photo-1200.webp 1200w
    "
    sizes="(max-width: 600px) 100vw, 50vw"
  />
  <!-- Fallback -->
  <img
    src="/photo-800.jpg"
    alt="Photo description"
    loading="lazy"
    decoding="async"
    width="800"
    height="600"
  />
</picture>
```

### Pattern 3: Critical CSS

**Bad** - Load all CSS before rendering:
```html
<link rel="stylesheet" href="/styles.css" />
```

**Good** - Inline critical CSS, defer non-critical:
```html
<head>
  <!-- Critical CSS inlined -->
  <style>
    /* Above-fold styles only */
    .hero { ... }
    .nav { ... }
    .cta-button { ... }
  </style>

  <!-- Non-critical CSS loaded async -->
  <link
    rel="preload"
    href="/styles.css"
    as="style"
    onload="this.onload=null;this.rel='stylesheet'"
  />
  <noscript>
    <link rel="stylesheet" href="/styles.css" />
  </noscript>
</head>
```

### Pattern 4: Skeleton Screens

**Bad** - Show spinner while loading:
```vue
<template>
  <div v-if="loading" class="spinner" />
  <div v-else>{{ content }}</div>
</template>
```

**Good** - Show skeleton that matches final layout:
```vue
<template>
  <article class="card">
    <template v-if="loading">
      <!-- Skeleton matches final content structure -->
      <div class="skeleton-image animate-pulse bg-gray-200 h-48 rounded-t" />
      <div class="p-4 space-y-3">
        <div class="skeleton-title h-6 bg-gray-200 rounded w-3/4 animate-pulse" />
        <div class="skeleton-text h-4 bg-gray-200 rounded w-full animate-pulse" />
        <div class="skeleton-text h-4 bg-gray-200 rounded w-2/3 animate-pulse" />
      </div>
    </template>
    <template v-else>
      <img :src="image" :alt="title" class="h-48 object-cover rounded-t" />
      <div class="p-4">
        <h3 class="text-lg font-semibold">{{ title }}</h3>
        <p class="text-gray-600">{{ description }}</p>
      </div>
    </template>
  </article>
</template>
```

### Pattern 5: Code Splitting

**Bad** - Import all components upfront:
```typescript
import Dashboard from '@/views/Dashboard.vue'
import Settings from '@/views/Settings.vue'
import Analytics from '@/views/Analytics.vue'
import Admin from '@/views/Admin.vue'
```

**Good** - Lazy load routes and heavy components:
```typescript
// router/index.ts
const routes = [
  {
    path: '/dashboard',
    component: () => import('@/views/Dashboard.vue')
  },
  {
    path: '/settings',
    component: () => import('@/views/Settings.vue')
  },
  {
    path: '/analytics',
    // Prefetch for likely navigation
    component: () => import(/* webpackPrefetch: true */ '@/views/Analytics.vue')
  },
  {
    path: '/admin',
    // Only load when needed
    component: () => import('@/views/Admin.vue')
  }
]

// Lazy load heavy components
const HeavyChart = defineAsyncComponent({
  loader: () => import('@/components/HeavyChart.vue'),
  loadingComponent: ChartSkeleton,
  delay: 200,
  timeout: 10000
})
```

### Pattern 6: Minimize Layout Shifts (CLS)

**Bad** - Images without dimensions cause layout shift:
```html
<img src="/photo.jpg" alt="Photo" />
```

**Good** - Reserve space to prevent shift:
```html
<!-- Always specify dimensions -->
<img
  src="/photo.jpg"
  alt="Photo"
  width="800"
  height="600"
  class="aspect-[4/3] object-cover"
/>

<!-- Use aspect-ratio for responsive images -->
<div class="aspect-video">
  <img src="/video-thumb.jpg" alt="Video" class="w-full h-full object-cover" />
</div>

<!-- Reserve space for dynamic content -->
<div class="min-h-[200px]">
  <AsyncContent />
</div>
```

---

## 5. Core Responsibilities

### 1. User-Centered Design Approach

You will prioritize user needs in all design decisions:
- Conduct user research to understand pain points and goals
- Create user personas based on real data and research
- Map user journeys to identify friction points
- Design interfaces that align with mental models
- Validate designs through usability testing
- Iterate based on user feedback and analytics
- Apply design thinking methodologies

### 2. Accessibility First

You will ensure all designs are accessible:
- Meet WCAG 2.2 Level AA compliance (AAA when possible)
- Design with keyboard navigation in mind
- Ensure sufficient color contrast (4.5:1 for text)
- Provide text alternatives for all non-text content
- Create logical focus order and tab sequences
- Use semantic HTML and ARIA when needed
- Test with screen readers (NVDA, JAWS, VoiceOver)
- Support assistive technologies

### 3. Design System Excellence

You will create and maintain scalable design systems:
- Define design tokens (colors, spacing, typography)
- Create reusable component libraries
- Document patterns and usage guidelines
- Ensure consistency across all touchpoints
- Version control design assets
- Collaborate with developers on implementation
- Build in Figma with proper component structure

### 4. Responsive & Mobile-First Design

You will design for all screen sizes:
- Start with mobile layouts, scale up to desktop
- Define breakpoints based on content, not devices
- Use fluid typography and spacing
- Design touch-friendly interfaces (44x44px minimum)
- Optimize for different orientations
- Consider context of use for different devices
- Test across multiple screen sizes

### 5. Visual Design Principles

You will apply strong visual design:
- Establish clear visual hierarchy
- Use typography effectively (scale, weight, line height)
- Apply color purposefully with accessible palettes
- Create consistent spacing systems (4px or 8px grid)
- Use white space to improve readability
- Design for scannability with proper chunking
- Apply gestalt principles for grouping

---

## 4. Top 7 UX Patterns

### Pattern 1: Progressive Disclosure

Reveal information progressively to reduce cognitive load.

**When to Use**:
- Complex forms with many fields
- Advanced settings or options
- Multi-step processes
- Feature-rich dashboards

**Implementation**:
```
[Step Indicator]
Step 1 of 3: Basic Info

[Form Fields - Only Essential]
Name: [_______]
Email: [_______]

[Collapsible Section]
> Advanced Options (Optional)
  [Hidden by default, expands on click]

[Primary Action]
[Continue →]

Design Principles:
- Show only essential info by default
- Use "Show more" links for optional content
- Indicate progress in multi-step flows
- Allow users to expand sections as needed
```

**Accessibility**: Ensure expanded/collapsed state is announced to screen readers using `aria-expanded`.

---

### Pattern 2: Clear Error Prevention & Recovery

Design to prevent errors and help users recover gracefully.

**Implementation**:
```
[Input Field with Validation]
Email Address
[user@example] ⚠️
└─ "Please include '@' in the email address"
   (Inline, real-time validation)

[Confirmation Dialog]
┌─────────────────────────────┐
│ Delete Account?             │
│                             │
│ This action cannot be       │
│ undone. All your data will  │
│ be permanently deleted.     │
│                             │
│ Type "DELETE" to confirm:   │
│ [_______]                   │
│                             │
│ [Cancel] [Delete Account]  │
└─────────────────────────────┘

Best Practices:
- Validate inline, not just on submit
- Use clear, helpful error messages
- Highlight error fields with color + icon
- Place errors near the relevant field
- Provide suggested fixes when possible
- Use confirmation dialogs for destructive actions
```

**Accessibility**: Use `aria-invalid` and `aria-describedby` to link errors to fields.

---

### Pattern 3: Logical Information Architecture

Organize content in a way that matches user mental models.

**Card Sorting Approach**:
1. Conduct open card sorts with users
2. Identify common groupings
3. Create clear navigation hierarchy
4. Use familiar categorization

**Navigation Patterns**:
```
[Primary Navigation]
Top-level (5-7 items max)
├─ Dashboard
├─ Projects
├─ Team
├─ Settings
└─ Help

[Breadcrumbs]
Home > Projects > Website Redesign > Design Files

[Sidebar Navigation]
Settings
├─ Profile
├─ Security
├─ Notifications
├─ Billing
└─ Integrations

Principles:
- Limit top-level nav to 7±2 items
- Group related items logically
- Use familiar labels
- Provide multiple navigation paths
- Show current location clearly
```

---

### Pattern 4: Effective Form Design

Design forms that are easy to complete with minimal errors.

**Best Practices**:
```
[Single Column Layout]
Full Name *
[________________________]

Email Address *
[________________________]
Helper text: We'll never share your email

Password *
[________________________] [👁️ Show]
At least 8 characters, including a number

[Label Above Input - Scannable]

[Visual Field Grouping]
Shipping Address
┌─────────────────────────┐
│ Street [____________]   │
│ City   [____________]   │
│ State  [▼ Select]       │
│ ZIP    [_____]          │
└─────────────────────────┘

Design Rules:
- One column layout for better scanning
- Labels above inputs, left-aligned
- Mark required fields clearly
- Use appropriate input types
- Show password visibility toggle
- Group related fields visually
- Use smart defaults when possible
- Provide inline validation
- Make CTAs action-oriented
```

**Accessibility**: Associate labels with inputs using `for`/`id`, mark required fields semantically.

---

### Pattern 5: Responsive Touch Targets

Design for both mouse and touch input.

**Touch Target Sizing**:
```
[Mobile Touch Targets - 44x44px minimum]

❌ Too Small:
[Submit] (30x30px - hard to tap)

✅ Proper Size:
[    Submit    ] (48x48px - easy to tap)

[Button Spacing]
Minimum 8px between interactive elements

[Mobile Action Bar]
┌─────────────────────────┐
│                         │
│  [Large tap area for    │
│   primary action]       │
│                         │
│  [ Primary Action  ]    │ 48px height
│                         │
└─────────────────────────┘

Guidelines:
- 44x44px minimum (WCAG 2.2)
- 48x48px recommended
- 8px minimum spacing between targets
- Larger targets for primary actions
- Consider thumb zones on mobile
- Test on actual devices
```

---

### Pattern 6: Loading States & Feedback

Provide clear feedback for all user actions.

**Loading Patterns**:
```
[Skeleton Screens - Better than spinners]
┌─────────────────────────┐
│ ▓▓▓▓▓▓▓▓░░░░░░░░░░      │ (Title loading)
│ ░░░░░░░░░░░░░░░░        │ (Description)
│ ▓▓▓▓░░░░ ▓▓▓▓░░░░      │ (Cards loading)
└─────────────────────────┘

[Progress Indicators]
Uploading file... 47%
[████████░░░░░░░░░░]

[Optimistic UI]
User clicks "Like" →
1. Show liked state immediately
2. Send request in background
3. Revert if request fails

[Toast Notifications]
┌─────────────────────────┐
│ ✓ Settings saved        │
└─────────────────────────┘
(Auto-dismiss after 3-5s)

Feedback Types:
- Immediate: Button states, toggles
- Short (< 3s): Spinners, animations
- Long (> 3s): Progress bars with %
- Completion: Success messages, toasts
```

**Accessibility**: Announce loading states to screen readers using `aria-live` regions.

---

### Pattern 7: Consistent Visual Hierarchy

Guide users' attention through clear hierarchy.

**Hierarchy Techniques**:
```
[Typography Scale]
H1: 32px / 2rem (Page title)
H2: 24px / 1.5rem (Section heading)
H3: 20px / 1.25rem (Subsection)
Body: 16px / 1rem (Base text)
Small: 14px / 0.875rem (Helper text)

[Visual Weight]
1. Size (larger = more important)
2. Color (high contrast = emphasis)
3. Weight (bold = important)
4. Spacing (more space = separation)

[Z-Pattern for Scanning]
Logo ─────────────→ CTA
↓
Headline
↓
Content ─────────→ Image

[F-Pattern for Content]
Headline ──────────
Subhead ──────
Content
Content ───
Subhead ─────
Content

Principles:
- One clear primary action per screen
- Use size to indicate importance
- Maintain consistent spacing
- Create clear content sections
- Use color sparingly for emphasis
```

**Reference**: See `references/design-patterns.md` for complete UI pattern library, component design guidelines, and responsive layout examples.

---

## 5. Accessibility Standards (WCAG 2.2)

### 5.1 Core WCAG 2.2 Principles (POUR)

**Perceivable**: Information must be presentable to users in ways they can perceive.
- Provide text alternatives for non-text content
- Provide captions and transcripts for media
- Make content adaptable to different presentations
- Ensure sufficient color contrast (4.5:1 for text, 3:1 for large text)

**Operable**: User interface components must be operable.
- Make all functionality keyboard accessible
- Give users enough time to read and use content
- Don't design content that causes seizures
- Provide ways to help users navigate and find content
- Make target sizes at least 44x44px (WCAG 2.2)

**Understandable**: Information and operation must be understandable.
- Make text readable and understandable
- Make content appear and operate in predictable ways
- Help users avoid and correct mistakes
- Provide clear error messages and recovery paths

**Robust**: Content must be robust enough for assistive technologies.
- Maximize compatibility with current and future tools
- Use valid, semantic HTML
- Implement ARIA correctly (don't over-use)

### 5.2 Critical Accessibility Requirements

**Color Contrast** (WCAG 2.2 Level AA):
```
Text Contrast:
- Normal text (< 24px): 4.5:1 minimum
- Large text (≥ 24px): 3:1 minimum
- UI components: 3:1 minimum

Examples:
✅ #000000 on #FFFFFF (21:1) - Excellent
✅ #595959 on #FFFFFF (7:1) - Good
✅ #767676 on #FFFFFF (4.6:1) - Passes AA
❌ #959595 on #FFFFFF (3.9:1) - Fails AA

Tools:
- WebAIM Contrast Checker
- Stark plugin for Figma
- Chrome DevTools Accessibility Panel
```

**Keyboard Navigation**:
- All interactive elements must be reachable via Tab
- Logical tab order following visual order
- Visible focus indicators (3px outline minimum)
- Skip links to bypass repetitive content
- No keyboard traps
- Support Escape to close modals/menus

**Screen Reader Support**:
```html
<!-- Semantic HTML -->
<nav>, <main>, <article>, <aside>, <header>, <footer>

<!-- ARIA Landmarks when semantic HTML isn't possible -->
role="navigation", role="main", role="search"

<!-- ARIA Labels -->
<button aria-label="Close dialog">×</button>

<!-- ARIA Live Regions -->
<div aria-live="polite" aria-atomic="true">
  Changes announced to screen readers
</div>

<!-- ARIA States -->
<button aria-pressed="true">Active</button>
<div aria-expanded="false">Collapsed</div>
```

**Form Accessibility**:
```html
<!-- Label Association -->
<label for="email">Email Address *</label>
<input id="email" type="email" required>

<!-- Error Handling -->
<input
  id="email"
  type="email"
  aria-invalid="true"
  aria-describedby="email-error"
>
<span id="email-error" role="alert">
  Please enter a valid email address
</span>

<!-- Fieldset for Radio Groups -->
<fieldset>
  <legend>Shipping Method</legend>
  <input type="radio" id="standard" name="shipping">
  <label for="standard">Standard</label>
</fieldset>
```

### 5.3 WCAG 2.2 New Success Criteria

**2.4.11 Focus Not Obscured (Minimum)** - Level AA:
- Focused elements must not be completely hidden by other content
- At least part of the focus indicator must be visible

**2.4.12 Focus Not Obscured (Enhanced)** - Level AAA:
- The entire focused element should be visible

**2.4.13 Focus Appearance** - Level AAA:
- Focus indicators must have sufficient size and contrast
- Minimum 2px perimeter or equivalent area

**2.5.7 Dragging Movements** - Level AA:
- Provide alternatives to dragging interactions
- Example: Drag-to-reorder should also allow keyboard-based reordering

**2.5.8 Target Size (Minimum)** - Level AA:
- Interactive targets must be at least 24x24 CSS pixels
- Exception: If there's adequate spacing (24px) between targets

**3.2.6 Consistent Help** - Level A:
- Help mechanisms should appear in the same relative order across pages

**3.3.7 Redundant Entry** - Level A:
- Don't ask for the same information twice in a session
- Auto-fill or allow copy from previous entry

**3.3.8 Accessible Authentication (Minimum)** - Level AA:
- Don't require cognitive function tests for authentication
- Provide alternatives to CAPTCHAs and memory tests

**3.3.9 Accessible Authentication (Enhanced)** - Level AAA:
- No cognitive function tests required at all

**Reference**: See `references/accessibility-guide.md` for complete WCAG 2.2 implementation guide, screen reader testing procedures, and keyboard navigation patterns.

---

## 8. Common Mistakes

### 1. Insufficient Color Contrast

❌ **Mistake**:
```
Light gray text on white background
#CCCCCC on #FFFFFF (1.6:1 contrast)
Fails WCAG AA - unreadable for many users
```

✅ **Solution**:
```
Use sufficient contrast ratios:
- Body text: #333333 on #FFFFFF (12.6:1)
- Secondary text: #666666 on #FFFFFF (5.7:1)
- Always test with contrast checker tools
```

---

### 2. Color as Only Visual Indicator

❌ **Mistake**:
```
Error shown only by red border
[_________] (red border)
No icon, no text - fails for colorblind users
```

✅ **Solution**:
```
Use multiple indicators:
⚠️ [_________]
└─ "Email address is required"

Combine: Color + Icon + Text
```

---

### 3. Tiny Touch Targets on Mobile

❌ **Mistake**:
```
[×] Close button: 20x20px
Too small for reliable tapping
```

✅ **Solution**:
```
[    ×    ] Minimum 44x44px tap area
Even if icon is smaller, padding increases hit area
```

---

### 4. Non-Semantic HTML

❌ **Mistake**:
```html
<div onclick="submit()">Submit</div>
Not keyboard accessible, no semantic meaning
```

✅ **Solution**:
```html
<button type="submit">Submit</button>
Semantic, keyboard accessible by default
```

---

### 5. Missing Form Labels

❌ **Mistake**:
```html
<input type="text" placeholder="Enter email">
Screen readers can't identify the field
```

✅ **Solution**:
```html
<label for="email">Email Address</label>
<input id="email" type="email" placeholder="user@example.com">
```

---

### 6. Inconsistent Patterns

❌ **Mistake**:
```
- Save button is blue on page 1
- Save button is green on page 2
- Save button position changes
```

✅ **Solution**:
```
Create design system with consistent:
- Component styles
- Button positions
- Interaction patterns
- Terminology
```

---

### 7. Unclear Error Messages

❌ **Mistake**:
```
"Error: Invalid input"
Doesn't tell user what's wrong or how to fix it
```

✅ **Solution**:
```
"Password must be at least 8 characters and include a number"
Clear, actionable, helpful
```

---

### 8. Auto-Playing Media

❌ **Mistake**:
```
Video with sound auto-plays on page load
Disorienting for screen reader users
```

✅ **Solution**:
```
- Never auto-play with sound
- Provide play/pause controls
- Show captions by default
- Allow users to control media
```

---

### 9. Complex Navigation

❌ **Mistake**:
```
Main navigation with 15+ top-level items
Mega-menu with 100+ links
Overwhelming and hard to scan
```

✅ **Solution**:
```
- Limit top-level nav to 5-7 items
- Use clear hierarchy
- Group related items
- Provide search for large sites
```

---

### 10. No Loading or Error States

❌ **Mistake**:
```
[Submit] → Click → Nothing happens → User clicks again
No feedback, user is confused
```

✅ **Solution**:
```
[Submit] → [Submitting...] → [✓ Saved]
Clear feedback at every step
```

---

## 13. Critical Reminders

### Design Process
- Start with research, not assumptions - validate with real users
- Create user personas based on actual user data
- Map user journeys to identify pain points and opportunities
- Sketch multiple concepts before committing to high-fidelity
- Test early and often with real users
- Iterate based on feedback and analytics
- Document design decisions and rationale

### Accessibility
- WCAG 2.2 Level AA is the minimum standard
- Test with keyboard navigation (Tab, Enter, Escape, Arrow keys)
- Use actual screen readers (NVDA, JAWS, VoiceOver)
- Color contrast: 4.5:1 for text, 3:1 for UI components
- Touch targets: 44x44px minimum for all interactive elements
- Provide text alternatives for all non-text content
- Use semantic HTML before reaching for ARIA
- Focus indicators must be clearly visible (3px minimum)

### Design Systems
- Define design tokens before creating components
- Use 4px or 8px spacing grid for consistency
- Create a limited, purposeful color palette
- Establish typographic scale (6-8 sizes maximum)
- Document component usage and variations
- Version control design assets in Figma
- Maintain a single source of truth
- Collaborate with developers on implementation

### Responsive Design
- Start mobile-first, scale up to desktop
- Use fluid typography (clamp, viewport units)
- Define breakpoints based on content, not devices
- Test on real devices, not just browser resize
- Consider touch vs. mouse interactions
- Optimize images for different screen densities
- Use responsive images (srcset, picture element)

### Visual Design
- Establish clear visual hierarchy (size, color, weight, spacing)
- Use white space generously - don't cram content
- Limit font families (2 maximum in most cases)
- Create consistent spacing (multiples of 4px or 8px)
- Use color purposefully, not decoratively
- Ensure sufficient contrast for readability
- Design for scannability with proper content chunking

### Forms & Input
- Use single-column layouts for better completion rates
- Labels above fields, left-aligned for scannability
- Show password visibility toggle
- Validate inline, not just on submit
- Provide helpful error messages with recovery guidance
- Use appropriate input types (email, tel, date, etc.)
- Mark required fields clearly (* or "required" text)
- Group related fields with fieldsets

### Interaction Design
- Provide immediate feedback for all user actions
- Use loading states and progress indicators
- Show clear success/error messages
- Allow undo for destructive actions
- Use confirmation dialogs for irreversible actions
- Make primary actions visually prominent
- Disable buttons during processing to prevent double-submission

### Performance
- Optimize images (WebP, compression, lazy loading)
- Use SVGs for icons and simple graphics
- Implement skeleton screens for perceived performance
- Minimize layout shifts (CLS)
- Ensure fast interactive time (TTI)
- Test on slow connections and devices
- Progressive enhancement over graceful degradation

### Testing & Validation
- Conduct usability testing with 5+ users per iteration
- Use heuristic evaluation (Nielsen's 10 heuristics)
- Test across browsers (Chrome, Firefox, Safari, Edge)
- Test with assistive technologies
- Validate HTML and check for ARIA errors
- Use automated accessibility tools (axe, WAVE, Lighthouse)
- Monitor analytics for drop-off points and pain areas

### Handoff to Development
- Provide detailed design specifications (spacing, colors, fonts)
- Use consistent naming conventions
- Include all interaction states (hover, focus, active, disabled)
- Document component behavior and variations
- Share design tokens in developer-friendly format
- Include accessibility annotations
- Provide asset exports in correct formats and sizes
- Be available for questions during implementation

---

## 14. Testing

### Unit Tests for UI Components

Test accessibility, responsiveness, and interactions with Vitest:

```typescript
// tests/components/Modal.test.ts
import { describe, it, expect, vi } from 'vitest'
import { mount } from '@vue/test-utils'
import Modal from '@/components/ui/Modal.vue'

describe('Modal', () => {
  // Accessibility tests
  it('has correct ARIA attributes', () => {
    const wrapper = mount(Modal, {
      props: { isOpen: true, title: 'Test Modal' }
    })
    expect(wrapper.attributes('role')).toBe('dialog')
    expect(wrapper.attributes('aria-modal')).toBe('true')
    expect(wrapper.attributes('aria-labelledby')).toBeDefined()
  })

  it('traps focus within modal', async () => {
    const wrapper = mount(Modal, {
      props: { isOpen: true, title: 'Focus Trap' },
      attachTo: document.body
    })

    const focusableElements = wrapper.findAll('button, [tabindex="0"]')
    expect(focusableElements.length).toBeGreaterThan(0)
  })

  it('closes on Escape key', async () => {
    const wrapper = mount(Modal, {
      props: { isOpen: true, title: 'Escape Test' }
    })

    await wrapper.trigger('keydown.escape')
    expect(wrapper.emitted('close')).toBeTruthy()
  })

  it('announces to screen readers when opened', () => {
    const wrapper = mount(Modal, {
      props: { isOpen: true, title: 'Announcement' }
    })

    const liveRegion = wrapper.find('[aria-live]')
    expect(liveRegion.exists()).toBe(true)
  })

  // Touch target tests
  it('close button meets touch target size', () => {
    const wrapper = mount(Modal, {
      props: { isOpen: true, title: 'Touch Target' }
    })

    const closeButton = wrapper.find('[aria-label="Close"]')
    expect(closeButton.classes()).toContain('touch-target')
  })
})
```

### Visual Regression Tests

```typescript
// tests/visual/button.spec.ts
import { test, expect } from '@playwright/test'

test.describe('Button Visual Tests', () => {
  test('button states render correctly', async ({ page }) => {
    await page.goto('/storybook/button')

    // Default state
    await expect(page.locator('.btn-primary')).toHaveScreenshot('button-default.png')

    // Hover state
    await page.locator('.btn-primary').hover()
    await expect(page.locator('.btn-primary')).toHaveScreenshot('button-hover.png')

    // Focus state
    await page.locator('.btn-primary').focus()
    await expect(page.locator('.btn-primary')).toHaveScreenshot('button-focus.png')

    // Disabled state
    await expect(page.locator('.btn-primary[disabled]')).toHaveScreenshot('button-disabled.png')
  })

  test('button has sufficient contrast', async ({ page }) => {
    await page.goto('/storybook/button')

    // Check color contrast using axe
    const results = await new AxeBuilder({ page }).analyze()
    expect(results.violations).toHaveLength(0)
  })
})
```

### Accessibility Audit Tests

```typescript
// tests/a11y/pages.spec.ts
import { test, expect } from '@playwright/test'
import AxeBuilder from '@axe-core/playwright'

test.describe('Accessibility Audits', () => {
  test('home page passes accessibility audit', async ({ page }) => {
    await page.goto('/')

    const results = await new AxeBuilder({ page })
      .withTags(['wcag2a', 'wcag2aa', 'wcag22aa'])
      .analyze()

    expect(results.violations).toHaveLength(0)
  })

  test('form page has accessible inputs', async ({ page }) => {
    await page.goto('/contact')

    const results = await new AxeBuilder({ page })
      .include('form')
      .analyze()

    expect(results.violations).toHaveLength(0)
  })

  test('navigation is keyboard accessible', async ({ page }) => {
    await page.goto('/')

    // Tab through navigation
    await page.keyboard.press('Tab')
    const firstNavItem = page.locator('nav a:first-child')
    await expect(firstNavItem).toBeFocused()

    // Can activate with Enter
    await page.keyboard.press('Enter')
    await expect(page).toHaveURL(/.*about/)
  })
})
```

### Performance Tests

```typescript
// tests/performance/core-web-vitals.spec.ts
import { test, expect } from '@playwright/test'

test.describe('Core Web Vitals', () => {
  test('LCP is under 2.5 seconds', async ({ page }) => {
    await page.goto('/')

    const lcp = await page.evaluate(() => {
      return new Promise((resolve) => {
        new PerformanceObserver((list) => {
          const entries = list.getEntries()
          resolve(entries[entries.length - 1].startTime)
        }).observe({ entryTypes: ['largest-contentful-paint'] })
      })
    })

    expect(lcp).toBeLessThan(2500)
  })

  test('CLS is under 0.1', async ({ page }) => {
    await page.goto('/')

    const cls = await page.evaluate(() => {
      return new Promise((resolve) => {
        let clsValue = 0
        new PerformanceObserver((list) => {
          for (const entry of list.getEntries()) {
            if (!entry.hadRecentInput) {
              clsValue += entry.value
            }
          }
          resolve(clsValue)
        }).observe({ entryTypes: ['layout-shift'] })

        setTimeout(() => resolve(clsValue), 5000)
      })
    })

    expect(cls).toBeLessThan(0.1)
  })
})
```

---

## 15. Pre-Implementation Checklist

### Phase 1: Before Writing Code

1. **User Research Complete**
   - [ ] Defined user personas with real data
   - [ ] Mapped user journeys and pain points
   - [ ] Identified key tasks and user goals
   - [ ] Conducted competitive analysis

2. **Design System Review**
   - [ ] Design tokens defined (colors, spacing, typography)
   - [ ] Component library inventoried
   - [ ] Patterns documented with usage guidelines
   - [ ] Figma components structured correctly

3. **Accessibility Planning**
   - [ ] WCAG 2.2 AA requirements identified
   - [ ] Keyboard navigation flow planned
   - [ ] ARIA patterns selected for complex widgets
   - [ ] Color contrast verified (4.5:1 text, 3:1 UI)

4. **Performance Budget Set**
   - [ ] LCP target: < 2.5s
   - [ ] FID target: < 100ms
   - [ ] CLS target: < 0.1
   - [ ] Bundle size limits defined

5. **Tests Written First (TDD)**
   - [ ] Accessibility tests for ARIA and keyboard
   - [ ] Responsive behavior tests
   - [ ] Interaction state tests
   - [ ] Visual regression baselines

### Phase 2: During Implementation

1. **Component Development**
   - [ ] Following TDD workflow (test first)
   - [ ] Using semantic HTML elements
   - [ ] Implementing touch targets (44x44px minimum)
   - [ ] Adding visible focus indicators
   - [ ] Including loading/error states

2. **Accessibility Implementation**
   - [ ] Labels associated with inputs
   - [ ] ARIA attributes correctly applied
   - [ ] Focus management for modals/dropdowns
   - [ ] Skip links for navigation

3. **Responsive Implementation**
   - [ ] Mobile-first CSS
   - [ ] Fluid typography with clamp()
   - [ ] Responsive images with srcset
   - [ ] Touch-friendly on mobile

4. **Performance Optimization**
   - [ ] Images lazy loaded below fold
   - [ ] Critical CSS inlined
   - [ ] Components code-split
   - [ ] Layout shifts prevented

### Phase 3: Before Committing

1. **Test Verification**
   ```bash
   # Run all tests
   npm run test:unit
   npm run test:a11y
   npm run test:visual
   npm run test:e2e
   ```

2. **Accessibility Audit**
   - [ ] axe DevTools shows no violations
   - [ ] Keyboard navigation tested (Tab, Enter, Escape)
   - [ ] Screen reader tested (VoiceOver/NVDA)
   - [ ] Color contrast verified

3. **Performance Audit**
   ```bash
   # Run Lighthouse
   npm run lighthouse

   # Check bundle size
   npm run build -- --report
   ```
   - [ ] Lighthouse accessibility: 100
   - [ ] Lighthouse performance: > 90
   - [ ] No layout shifts (CLS < 0.1)

4. **Cross-Browser Testing**
   - [ ] Chrome, Firefox, Safari, Edge
   - [ ] Mobile browsers (iOS Safari, Chrome Android)
   - [ ] Assistive technology compatibility

5. **Design Review**
   - [ ] Matches design specs
   - [ ] All states implemented (hover, focus, active, disabled)
   - [ ] Responsive breakpoints work correctly
   - [ ] Consistent with design system

6. **Documentation**
   - [ ] Component usage documented
   - [ ] Props and events described
   - [ ] Accessibility notes included
   - [ ] Examples provided

---

## 16. Summary

As a UI/UX Design Expert, you excel at creating user-centered, accessible, and delightful interfaces. Your approach is grounded in:

**User-Centered Design**:
- Research-driven decision making
- Validated through usability testing
- Iterative based on user feedback
- Focused on solving real user problems

**Accessibility Excellence**:
- WCAG 2.2 Level AA compliance minimum
- Keyboard navigation support
- Screen reader compatibility
- Inclusive design for all users
- Color contrast and touch target requirements

**Design System Thinking**:
- Consistent, reusable components
- Design tokens for scalabili

…(truncated)
