All skills

Review SwiftUI code for iOS/watchOS Human Interface Guidelines compliance, font usage, Dynamic Type support, and accessibility. Use when user mentions UI review, HIG, accessibility audit, font checks, or wants to verify interface design against Apple standards.

Use this Skill: https://skilld.dev/gh/rshankras/claude-code-apple-skills/ui-review

This session only. Nothing lands on disk.

hig-checklist.md

≈2.5k tokens on demand. Your agent reads this file only when SKILL.md points to it.

Human Interface Guidelines Checklist

Comprehensive checklist for iOS and watchOS HIG compliance.

iOS Human Interface Guidelines

Layout & Spacing

Safe Areas
  • Content respects safe area insets
  • .safeAreaInset() used for persistent content
  • .ignoresSafeArea() only for backgrounds/media
// ✅ Good
VStack {
    content
}
.safeAreaInset(edge: .bottom) {
    BottomBar()
}

// ✅ Good - Background extends
ZStack {
    Color.blue
        .ignoresSafeArea()
    content
}
Tap Targets
  • Minimum 44x44 points for all interactive elements
  • Adequate spacing between tappable elements
// ✅ Ensure minimum size
Button("Action") { }
    .frame(minWidth: 44, minHeight: 44)
Spacing
  • Consistent spacing using system values
  • .padding() for standard spacing
  • .padding(.horizontal) / .padding(.vertical) for directional
// ✅ Use system spacing
VStack(spacing: 16) {
    // Standard spacing
}

// ✅ Use padding
content
    .padding()
ScrollView
  • Long content uses ScrollView
  • Scroll indicators visible
  • Content offset considered

Navigation

NavigationStack (iOS 16+)
  • Use NavigationStack instead of deprecated NavigationView
  • Proper navigation title placement
  • Back button navigation works correctly
// ✅ Modern navigation
NavigationStack {
    List(items) { item in
        NavigationLink(value: item) {
            ItemRow(item: item)
        }
    }
    .navigationTitle("Items")
    .navigationBarTitleDisplayMode(.large)
    .navigationDestination(for: Item.self) { item in
        ItemDetailView(item: item)
    }
}
Navigation Patterns
  • Clear navigation hierarchy
  • Proper use of navigation modifiers
  • Toolbar items placed appropriately
// ✅ Toolbar placement
.toolbar {
    ToolbarItem(placement: .navigationBarTrailing) {
        Button("Add") { }
    }
}

Modality

Sheets
  • Sheets for focused tasks
  • Dismiss gesture available
  • Proper presentation detents on iOS 16+
// ✅ Proper sheet
.sheet(isPresented: $showingSheet) {
    AddItemView()
        .presentationDetents([.medium, .large])
        .presentationDragIndicator(.visible)
}
Alerts
  • Destructive actions marked with role
  • Cancel button provided
  • Clear, concise messaging
// ✅ Proper alert
.alert("Delete Item?", isPresented: $showingAlert) {
    Button("Delete", role: .destructive) {
        deleteItem()
    }
    Button("Cancel", role: .cancel) { }
} message: {
    Text("This action cannot be undone.")
}
Confirmation Dialogs
  • Use for multiple action choices
  • Destructive actions at top
  • Cancel at bottom
// ✅ Confirmation dialog
.confirmationDialog("Options", isPresented: $showingOptions) {
    Button("Delete", role: .destructive) { }
    Button("Archive") { }
    Button("Cancel", role: .cancel) { }
}

Colors & Visuals

Semantic Colors
  • Use semantic color names
  • Avoid hardcoded colors
  • Support both light and dark mode
// ✅ Semantic colors
.foregroundColor(.primary)      // Adapts to theme
.foregroundColor(.secondary)
.background(Color(.systemBackground))

// ❌ Hardcoded colors
.foregroundColor(.black)        // Doesn't adapt
.background(.white)
System Colors
  • Use UIColor system colors via Color()
  • Proper contrast in both modes
// ✅ System colors
Color(.systemRed)
Color(.systemBackground)
Color(.secondarySystemBackground)
Color(.label)
Color(.secondaryLabel)
Color Contrast
  • Normal text: 4.5:1 minimum
  • Large text (18pt+): 3.1 minimum
  • UI components: 3:1 minimum
  • Verify with Accessibility Inspector
SF Symbols
  • Use SF Symbols for icons
  • Consistent symbol style
  • Proper symbol rendering mode
// ✅ SF Symbols
Image(systemName: "plus.circle.fill")
    .symbolRenderingMode(.hierarchical)
    .imageScale(.large)

Lists & Collections

List Performance
  • Use id for stable identities
  • Provide IDs or use Identifiable
  • Efficient row updates
// ✅ Stable IDs
List(items, id: \.id) { item in
    ItemRow(item: item)
}

// ✅ Or Identifiable
struct Item: Identifiable {
    let id: UUID
}

List(items) { item in
    ItemRow(item: item)
}
List Actions
  • Swipe actions for common operations
  • Context menus for additional actions
  • Pull to refresh when appropriate
// ✅ Swipe actions
.swipeActions(edge: .trailing) {
    Button("Delete", role: .destructive) { }
}

// ✅ Context menu
.contextMenu {
    Button("Edit") { }
    Button("Delete", role: .destructive) { }
}

Forms & Input

Form Structure
  • Sections with headers
  • Grouped related fields
  • Clear labels
// ✅ Well-structured form
Form {
    Section("Basic Info") {
        TextField("Name", text: $name)
        TextField("Email", text: $email)
    }

    Section("Preferences") {
        Toggle("Notifications", isOn: $notifications)
        Picker("Theme", selection: $theme) {
            ForEach(Theme.allCases) { theme in
                Text(theme.rawValue).tag(theme)
            }
        }
    }
}
Input Validation
  • Real-time validation feedback
  • Clear error messages
  • Disable submit until valid
// ✅ Validation feedback
TextField("Email", text: $email)
    .textInputAutocapitalization(.never)
    .keyboardType(.emailAddress)
    .overlay(alignment: .trailing) {
        if !email.isEmpty && !isValidEmail {
            Image(systemName: "xmark.circle.fill")
                .foregroundColor(.red)
        }
    }

Loading & Empty States

Loading States
  • ProgressView for loading
  • Descriptive labels
  • Consider skeleton screens
// ✅ Loading state
if isLoading {
    ProgressView("Loading items...")
} else {
    ContentView()
}
Empty States
  • Helpful message when empty
  • Action to add first item
  • Icon or illustration
// ✅ Empty state
if items.isEmpty {
    ContentUnavailableView(
        "No Items",
        systemImage: "tray.fill",
        description: Text("Add your first item to get started")
    )
} else {
    List(items) { item in
        ItemRow(item: item)
    }
}
Error States
  • Clear error messaging
  • Retry action
  • Contact support option
// ✅ Error state
ContentUnavailableView(
    "Unable to Load",
    systemImage: "exclamationmark.triangle",
    description: Text("Please check your connection and try again")
) {
    Button("Retry") {
        loadData()
    }
}

watchOS Human Interface Guidelines

Layout

Screen Sizes
  • Support all watch sizes (38mm to 49mm)
  • Test on different screen sizes
  • Responsive layouts
Padding & Spacing
  • Larger padding than iOS (content closer to edges)
  • Clear visual hierarchy
  • Generous tap targets (40x40 minimum)
Scrolling
  • Use Lists for scrollable content
  • Digital Crown scroll support
  • Minimal horizontal scrolling

Interaction

Digital Crown
  • Support Digital Crown for scrolling
  • Use for value input when appropriate
  • Provide visual feedback
// ✅ Digital Crown input
@State private var value = 0.5

var body: some View {
    VStack {
        Text("Value: \(value, specifier: "%.2f")")
        Gauge(value: value, in: 0...1) {
            Text("Amount")
        }
    }
    .focusable()
    .digitalCrownRotation($value)
}
Tap Targets
  • Minimum 40x40 points
  • Full-width buttons when possible
  • Clear spacing between elements
Complications
  • Provide complications for quick access
  • Update complications regularly
  • Support multiple complication families

Navigation

Hierarchical Navigation
  • Clear navigation stack
  • Back navigation with edge swipe
  • Navigation titles
// ✅ watchOS navigation
NavigationStack {
    List(items) { item in
        NavigationLink(value: item) {
            Text(item.name)
        }
    }
    .navigationTitle("Items")
    .navigationDestination(for: Item.self) { item in
        ItemDetailView(item: item)
    }
}
Pages (Tab-like)
  • Use TabView for page-based navigation
  • Index dots visible
  • Swipe between pages
// ✅ Page-based navigation
TabView {
    ActivityView()
    SummaryView()
    SettingsView()
}
.tabViewStyle(.page)

Text & Fonts

Font Sizes
  • Larger than iOS equivalents
  • Support Dynamic Type
  • Test at largest sizes
// ✅ Appropriate watchOS fonts
Text("Title")
    .font(.headline)

Text("Body")
    .font(.body)
Text Length
  • Keep text concise
  • Truncate appropriately
  • Use abbreviations when sensible

Color & Contrast

High Contrast
  • Higher contrast than iOS
  • Test in both always-on modes
  • Consider outdoor visibility
Always-On Display
  • Dimmed content for always-on
  • Remove unnecessary animations
  • Reduce color saturation

Testing Checklist

Device Testing

  • Test on smallest device
  • Test on largest device
  • Test on mid-size devices

Orientation

  • iPad: All orientations
  • iPhone: Portrait and landscape
  • Adaptive layouts

Accessibility

  • VoiceOver navigation
  • Dynamic Type scaling
  • Reduce Motion
  • Increase Contrast

Visual Modes

  • Light mode
  • Dark mode
  • High contrast mode
  • Reduce transparency

References

Source: SKILL.md on GitHub

No alerts2mo3 checks · Risk SAFE
  • Gen Agent Trust Hub2mo

    The skill is a specialized tool for reviewing SwiftUI code against Apple's Human Interface Guidelines and accessibility standards. It operates safely by reading project files and referencing official Apple documentation. No malicious patterns, obfuscation, or high-risk behaviors were detected.

  • Socket2mo

    No alerts

  • Snyk2mo

    Risk: LOW · No issues

Signed by skilld at 32566aa. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub 2 months ago.

Steadyupdated 3 months ago
What it can do
Reads files Network
last_verified
2026-07-16
review_by
2027-06-22
All 4 allowed tools
ReadGlobGrepWebFetch

README badge

README badge for rshankras/claude-code-apple-skills/ui-review