> ## Documentation Index
> Fetch the complete documentation index at: https://docs.swiftaiboilerplate.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Accessibility Module

> Make your iOS app inclusive by default with VoiceOver, Dynamic Type, Reduce Motion, and High Contrast support

Every app deserves to be usable by everyone. The Accessibility module makes building inclusive iOS apps effortless with pre-defined labels, SwiftUI modifiers, and comprehensive support for iOS accessibility features.

<Info>
  **Package location:** `Packages/DesignSystem/Sources/DesignSystem/Accessibility/`
</Info>

## Overview

The Accessibility module is part of the DesignSystem package and provides ready-to-use accessibility features that work with VoiceOver, Dynamic Type, Reduce Motion, and High Contrast modes out of the box.

<CardGroup cols={2}>
  <Card title="Pre-defined VoiceOver Labels" icon="ear-listen">
    Typed labels for common UI patterns, ready to apply
  </Card>

  <Card title="Dynamic Type" icon="text-size">
    Text scales beautifully with user preferences
  </Card>

  <Card title="Reduce Motion" icon="bolt-slash">
    Respects motion sensitivity settings
  </Card>

  <Card title="High Contrast" icon="circle-half-stroke">
    Colors adapt for better readability
  </Card>
</CardGroup>

## Quick Start

### VoiceOver Labels

One line for full accessibility:

```swift theme={null}
import DesignSystem

// Apply pre-defined accessibility
Button("Send") { }
    .saiAccessible(A11y.Chat.sendButton)
// VoiceOver: "Send message, button. Double tap to send your message."

// Works for all common UI patterns
Image("avatar")
    .saiAccessible(A11y.Profile.photo)
// VoiceOver: "Profile photo. Double tap to change your profile photo."
```

### Dynamic Type Support

Text scales beautifully with user preferences:

```swift theme={null}
Text("Respects user settings")
    .saiScaledFont(size: 18, weight: .semibold, relativeTo: .body)
// Automatically scales with iOS text size settings
// Capped to prevent layout issues at extreme sizes
```

### Reduce Motion

Respects users who experience discomfort with animations:

```swift theme={null}
Button("Animate") { }
    .scaleEffect(isPressed ? 0.95 : 1.0)
    .saiReducedMotionAnimation(.spring())
// Animation plays normally OR instant state change
// Based on user's Reduce Motion setting
```

### High Contrast Mode

Colors adapt automatically for users who need more contrast:

```swift theme={null}
Text("Adapts to user needs")
    .saiContrastAwareForeground(
        normal: DSColors.textSecondary,
        highContrast: DSColors.textPrimary
    )
```

## File Structure

```text theme={null}
Packages/DesignSystem/Sources/DesignSystem/Accessibility/
├── A11y.swift          # Pre-defined labels (A11yLabel + A11y namespaces)
├── A11yModifiers.swift # SwiftUI modifiers (sai* View extensions)
└── A11yAudit.swift     # Debug-only audit overlay + checklist
```

## Pre-Defined Labels

The `A11y` enum groups typed `A11yLabel` values by feature. Use `A11y.<Group>.<label>` directly, or extend the enum with your own (see [Adding Custom Labels](#adding-custom-labels)).

<AccordionGroup>
  <Accordion title="A11y.Chat">
    `sendButton`, `messageInput`, `userMessage`, `assistantMessage`, `newChat`, `historyList`, `copyAction`, `deleteAction`
  </Accordion>

  <Accordion title="A11y.Auth">
    `signInApple`, `signInGoogle`, `emailInput`, `passwordInput`, `signOut`
  </Accordion>

  <Accordion title="A11y.Settings">
    `themeSelector`, `notificationsToggle`, `diagnosticsToggle`, `deleteAccount`
  </Accordion>

  <Accordion title="A11y.Profile">
    `photo`, `displayName`, `editButton`
  </Accordion>

  <Accordion title="A11y.Payments">
    `subscribeButton`, `restoreButton`, `planOption(name:price:)`, `subscriptionStatus(isSubscribed:)`
  </Accordion>

  <Accordion title="A11y.Navigation">
    `back`, `close`, `menu`, `tab(name:selected:)`
  </Accordion>

  <Accordion title="A11y.Common">
    `loading`, `error(message:)`, `success(message:)`, `dismiss`
  </Accordion>
</AccordionGroup>

## Adding Custom Labels

### 1. Define Your Label

```swift theme={null}
extension A11y {
    public enum MyFeature {
        public static let action = A11yLabel(
            label: "Custom action",
            hint: "Double tap to perform custom action"
        )
        
        public static let toggle = A11yLabel(
            label: "Enable feature",
            hint: "Double tap to toggle"
        )
    }
}
```

### 2. Apply to Views

```swift theme={null}
Button("Action") { }
    .saiAccessible(A11y.MyFeature.action)

Toggle("Feature", isOn: $enabled)
    .saiAccessible(A11y.MyFeature.toggle)
```

## SwiftUI Modifiers

### `.saiAccessible(_:)`

Apply a pre-defined accessibility label:

```swift theme={null}
Button("Send") { }
    .saiAccessible(A11y.Chat.sendButton)
```

### `.saiAccessibilityHidden()`

Hide decorative elements from VoiceOver:

```swift theme={null}
Image("background")
    .saiAccessibilityHidden()
```

### `.saiScaledFont(size:weight:relativeTo:)`

Dynamic Type-aware font sizing:

```swift theme={null}
Text("Title")
    .saiScaledFont(size: 24, weight: .bold, relativeTo: .title)
```

### `.saiReducedMotionAnimation(_:)`

Motion-sensitive animation:

```swift theme={null}
.saiReducedMotionAnimation(.spring(response: 0.3))
```

### `.saiContrastAwareForeground(normal:highContrast:)`

High contrast color adaptation:

```swift theme={null}
.saiContrastAwareForeground(
    normal: .secondary,
    highContrast: .primary
)
```

## Debug Tools

### Accessibility Audit Overlay

`accessibilityAuditOverlay(showWarnings:)` is a DEBUG-only modifier that adds a toggle button and a colored-legend overlay to a view during development. It is compiled out of Release builds.

```swift theme={null}
#Preview {
    MainContent()
        .accessibilityAuditOverlay()
}
```

The overlay legend flags:

* Red — critical issues (missing/empty labels, buttons without hints, images without labels, touch targets smaller than 44x44 points, insufficient contrast)
* Yellow — warnings (generic or overly long labels, missing traits, redundant labels)
* Green — accessible

For console output, `A11yAudit.printResults(_:)` prints issue and warning counts, and `A11yChecklist.printChecklist()` prints the manual review checklist.

## Testing Accessibility

### Unit Tests

```swift theme={null}
func testAccessibilityLabels() {
    // label is non-optional; hint is String?
    XCTAssertFalse(A11y.Chat.sendButton.label.isEmpty)
    XCTAssertEqual(A11y.Chat.sendButton.hint, "Double tap to send your message")
}
```

### UI Tests

```swift theme={null}
func testVoiceOverNavigation() throws {
    let app = XCUIApplication()
    app.launch()
    
    // Find the button by its accessibility label
    let sendButton = app.buttons["Send message"]
    XCTAssertTrue(sendButton.exists)
    
    // Verify accessibility hint
    XCTAssertEqual(
        sendButton.label,
        "Send message"
    )
}
```

### Manual Testing

<Steps>
  <Step title="Enable VoiceOver">
    Settings → Accessibility → VoiceOver → On
  </Step>

  <Step title="Navigate your app">
    Swipe right to move through elements
  </Step>

  <Step title="Verify announcements">
    Listen for clear, helpful descriptions
  </Step>

  <Step title="Test Dynamic Type">
    Settings → Display → Text Size → Largest
  </Step>
</Steps>

## Best Practices

<CardGroup cols={2}>
  <Card title="Label all interactive elements" icon="check">
    Buttons, links, and controls need labels
  </Card>

  <Card title="Hide decorative images" icon="eye-slash">
    Use `.saiAccessibilityHidden()` for backgrounds
  </Card>

  <Card title="Provide meaningful hints" icon="lightbulb">
    Describe what happens when activated
  </Card>

  <Card title="Test with real users" icon="users">
    Accessibility users find issues you miss
  </Card>
</CardGroup>

## Test Coverage

Accessibility helpers are covered through DesignSystem tests and should also be verified manually with VoiceOver, Dynamic Type, Reduce Motion, and high contrast settings on a simulator or device.

## Related

<CardGroup cols={2}>
  <Card title="Quick Start" href="/pages/quickstart">
    Run the app before auditing accessibility
  </Card>

  <Card title="Architecture" href="/pages/architecture">
    Understand module boundaries
  </Card>

  <Card title="Localization Module" href="/pages/modules/localization">
    Type-safe strings and i18n
  </Card>

  <Card title="Design System" href="/pages/modules/design-system">
    UI tokens and components
  </Card>
</CardGroup>
