Reference — Comprehensive Apple Human Interface Guidelines covering colors (semantic, custom, patterns), backgrounds (material hierarchy, dynamic), typography (built-in styles, custom fonts, Dynamic Type), SF Symbols (rendering modes, color, localization), Dark Mode, accessibility, and platform-specific considerations
Inherits all available tools
Additional assets for this skill
This skill inherits all available tools. When active, it can use any tool Claude has access to.
The Human Interface Guidelines (HIG) define Apple's design philosophy and provide concrete guidance for creating intuitive, accessible, platform-appropriate experiences across all Apple devices.
Every design decision should support these principles:
1. Clarity Content is paramount. Interface elements should defer to content, not compete with it. Every element has a purpose, unnecessary complexity is eliminated, and users should immediately know what they can do without extensive instructions.
2. Consistency Apps use standard UI elements and familiar patterns. Navigation follows platform conventions, gestures work as expected, and components appear in expected locations. This familiarity reduces cognitive load.
3. Deference The UI should not distract from essential content. Use subtle backgrounds, receding navigation when not needed, restrained branding, and let content be the hero.
From Apple HIG: "Deference makes an app beautiful by ensuring the content stands out while the surrounding visual elements do not compete with it."
From WWDC25: "A systematic approach means designing with intention at every level, ensuring that all elements, from the tiniest control to the largest surface, are considered in relation to the whole."
hig for quick decisions and checklistsliquid-glass for iOS 26 material implementationliquid-glass-ref for iOS 26 app-wide adoptionaccessibility-diag for accessibility troubleshootingInstead of hardcoded color values, use semantic colors that describe the purpose of a color rather than its appearance. Semantic colors automatically adapt to light/dark mode and accessibility settings.
Key insight from WWDC19: "Think of Dark Mode as having the lights dimmed rather than everything being flipped inside out." Colors are NOT simply inverted—table row backgrounds are lighter in both modes.
Use label colors for text and symbols:
// Primary content (most prominent)
Text("Title")
.foregroundStyle(.primary)
// Uses `label` color - black in Light Mode, white in Dark Mode
// Secondary content (subtitles, less prominent)
Text("Subtitle")
.foregroundStyle(.secondary)
// Uses `secondaryLabel` - gray tone
// Tertiary content (placeholder text)
Text("Placeholder")
.foregroundStyle(.tertiary)
// Uses `tertiaryLabel` - lighter gray
// Quaternary content (disabled text)
Text("Disabled")
.foregroundStyle(.quaternary)
// Uses `quaternaryLabel` - very light gray
Hierarchy: label → secondaryLabel → tertiaryLabel → quaternaryLabel
Background colors come in two sets: ungrouped and grouped.
For standard lists and views:
// Primary background (main background)
Color(.systemBackground)
// Pure white in Light Mode, pure black in Dark Mode
// Secondary background (information structure)
Color(.secondarySystemBackground)
// Light gray in Light Mode, dark gray in Dark Mode
// Tertiary background (further layering)
Color(.tertiarySystemBackground)
// Lighter than secondary, darker in Dark Mode
For grouped table views (iOS Settings style):
// Primary grouped background
Color(.systemGroupedBackground)
// Secondary grouped background
Color(.secondarySystemGroupedBackground)
// Tertiary grouped background
Color(.tertiarySystemGroupedBackground)
Usage:
// Standard list
List {
Text("Item")
}
.background(Color(.systemBackground))
// Grouped list (Settings style)
List {
Section("Section 1") {
Text("Item")
}
}
.listStyle(.grouped)
There are actually two sets of background colors for layering interfaces:
Why this matters:
In Light Mode, simple drop shadows create visual separation. In Dark Mode, drop shadows are less effective, so the system uses lighter colors for elevated content.
Example: iPad multitasking:
Critical: Some darker colors may not contrast well when elevated. Always test designs in elevated state. Semi-opaque fill and separator colors adapt gracefully.
Tint colors are dynamic - they have variants for Light and Dark modes:
// Tint color automatically adapts
Button("Primary Action") {
// action
}
.tint(.blue)
// Gets lighter in Dark Mode, darker in Light Mode
Custom tint colors: When creating custom tint colors, select colors that work well in both modes. Use a contrast calculator to aim for 4.5:1 or higher contrast ratio. Colors that work in Light Mode may have insufficient contrast in Dark Mode.
Fill colors are semi-transparent to contrast well against variable backgrounds:
// System fill colors
Color(.systemFill)
Color(.secondarySystemFill)
Color(.tertiarySystemFill)
Color(.quaternarySystemFill)
When to use: Controls, buttons, and interactive elements that need to appear above dynamic backgrounds.
// Standard separator (semi-transparent)
Color(.separator)
// Opaque separator
Color(.opaqueSeparator)
Opaque separators are used when transparency would create undesirable results (e.g., intersecting grid lines where overlapping semi-transparent colors create optical illusions).
Apple's explicit guidance:
"In rare cases, consider using only a dark appearance in the interface. For example, it can make sense for an app that enables immersive media viewing to use a permanently dark appearance that lets the UI recede and helps people focus on the media."
Examples from Apple's apps:
| App | Background | Rationale |
|---|---|---|
| Music | Dark | Album art should be visual focus |
| Photos | Dark | Images are hero content |
| Clock | Dark | Nighttime use, instrument feel |
| Stocks | Dark | Data visualization, charts |
| Camera | Dark | Reduces distraction during capture |
For all other apps: Support both Light and Dark modes via system backgrounds.
When you need custom colors:
// Use custom color from asset catalog
Color("BrandAccent")
// Automatically uses correct variant
San Francisco (SF): The system sans-serif font family.
New York (NY): System serif font family for editorial content.
Both available as variable fonts with seamless weight transitions.
From Apple HIG: "Avoid light font weights. Prefer Regular, Medium, Semibold, or Bold weights instead of Ultralight, Thin, or Light."
Why: Light weights have legibility issues, especially at small sizes, in bright lighting, or for users with visual impairments.
Hierarchy:
// Headers - Bold weight for prominence
Text("Header")
.font(.title.weight(.bold))
// Subheaders - Semibold
Text("Subheader")
.font(.title2.weight(.semibold))
// Body - Regular or Medium
Text("Body text")
.font(.body)
// Captions - Regular (never Light)
Text("Caption")
.font(.caption)
Use built-in text styles for automatic hierarchy and Dynamic Type support:
.font(.largeTitle) // Largest
.font(.title) // Page titles
.font(.title2) // Section headers
.font(.title3) // Sub-section headers
.font(.headline) // Emphasized body
.font(.body) // Default body text
.font(.callout) // Slightly emphasized
.font(.subheadline) // Less prominent
.font(.footnote) // Auxiliary info
.font(.caption) // Minimal emphasis
.font(.caption2) // Smallest
Requirement: Apps must support text scaling of at least 200% (iOS, iPadOS) or 140% (watchOS).
Implementation:
// ✅ CORRECT - Scales automatically
Text("Hello")
.font(.body)
// ❌ WRONG - Fixed size, doesn't scale
Text("Hello")
.font(.system(size: 17))
Layout considerations:
Not all content scales equally: Prioritize what users actually care about. Secondary elements like tab titles shouldn't grow as much as primary content.
When using custom fonts:
If your custom font is thin: Increase size by ~2 points when pairing with uppercase Latin text.
Loose leading: Wide columns (easier to track to next line) Tight leading: Constrained height (avoid for 3+ lines)
// Adjust leading for specific layouts
Text("Long content...")
.lineSpacing(8) // Add space between lines
From WWDC25: "There's a quiet geometry to how our shapes fit together, driven by concentricity. By aligning radii and margins around a shared center, shapes can comfortably nest within each other."
Constant corner radius regardless of size:
RoundedRectangle(cornerRadius: 12)
Use when: You need a specific, unchanging corner radius.
Radius is half the container's height:
Capsule()
Use when: You want shapes that adapt to content while maintaining rounded ends. Perfect for buttons, pills, and controls.
Found throughout iOS 26: Sliders, switches, grouped table views, tab bars, navigation bars.
Calculate radius by subtracting padding from parent's radius:
.containerRelativeShape(.roundedRectangle)
Use when: Nesting shapes within containers to maintain visual harmony.
Hardware ↔ Software harmony: Apple's hardware features consistent bezel curvature. The same precision now guides UI, with curvature, size, and proportion aligning to create unified rhythm between what you hold and what you see.
Example of concentricity:
Window (rounded corners)
├─ Sheet (concentric to window)
│ ├─ Card (concentric to sheet)
│ │ └─ Button (concentric to card)
iOS:
macOS:
To preserve optical balance, views are:
Example: Asymmetric icons may need padding adjustments for optical centering rather than geometric centering.
Materials allow background content to show through, creating visual depth and hierarchy.
Choosing thickness:
// Apply material
.background(.ultraThinMaterial)
.background(.thinMaterial)
.background(.regularMaterial)
.background(.thickMaterial)
Key principle: Use vibrant colors on top of materials for legibility. Solid colors can get muddy depending on background context. Vibrancy maintains contrast regardless of background.
// Vibrant text on material
VStack {
Text("Primary")
.foregroundStyle(.primary) // Vibrant
Text("Secondary")
.foregroundStyle(.secondary) // Vibrant
}
.background(.regularMaterial)
Purpose: Creates a distinct functional layer for controls and navigation, floating above content.
Two variants:
Regular Liquid Glass
Clear Liquid Glass
Cross-reference: See liquid-glass skill for implementation details and liquid-glass-ref for comprehensive adoption guide.
Place items to convey their relative importance:
From Apple HIG: "Make essential information easy to find by giving it sufficient space and avoid obscuring it with nonessential details."
Group related items using:
Ensure content and controls remain clearly distinct through Liquid Glass material and scroll edge effects.
"Extend content to fill the screen or window" with backgrounds and artwork reaching display edges.
Background extension views: Use when content doesn't naturally span the full window.
// Content extends to edges
VStack {
FullWidthImage()
.ignoresSafeArea() // Extends to screen edges
}
Safe Areas: Rectangular regions unobstructed by:
Layout Guides: Define rectangular regions for positioning and spacing content with:
Key principle: "Respect key display and system features in each platform."
// Respect safe areas
VStack {
Text("Content")
}
.safeAreaInset(edge: .bottom) {
BottomBar()
}
"Align components with one another to make them easier to scan."
Grid alignment:
Design layouts that:
Requirements:
WCAG Level AA standards:
Implementation:
// ✅ Use semantic colors (automatic contrast)
Text("Label").foregroundStyle(.primary)
// ❌ Custom colors may fail contrast
Text("Label").foregroundStyle(.gray) // Check with calculator
High contrast mode: Provide higher contrast color schemes when "Increase Contrast" accessibility setting is enabled.
Test in both Light and Dark modes.
Critical: "Convey information with more than color alone" to support colorblind users.
Solutions:
Example:
// ❌ Only color indicates status
Circle().fill(isActive ? .green : .red)
// ✅ Shape + color
HStack {
Image(systemName: isActive ? "checkmark.circle.fill" : "xmark.circle.fill")
Text(isActive ? "Active" : "Inactive")
}
.foregroundStyle(isActive ? .green : .red)
Describe interface and content for VoiceOver accessibility:
Button {
share()
} label: {
Image(systemName: "square.and.arrow.up")
}
.accessibilityLabel("Share")
For video/audio content, provide:
Pair audio signals with:
Touch targets:
Gestures:
Assistive technologies:
Respect "Reduce Motion":
// Check Reduce Motion setting
@Environment(\.accessibilityReduceMotion) var reduceMotion
var body: some View {
content
.animation(reduceMotion ? nil : .spring(), value: isExpanded)
}
Offer adjustable difficulty levels.
Prioritize comfort:
Purposeful Animation: "Add motion purposefully, supporting the experience without overshadowing it."
Avoid gratuitous animations that distract or cause discomfort. Motion should enhance rather than dominate the interface.
Make motion optional. Supplement visual feedback with haptics and audio to communicate important information, ensuring all users can understand your interface regardless of motion preferences.
Design animations aligned with user expectations and gestures. Feedback should be:
Avoid animating frequent UI interactions. Standard system elements already include subtle animations, so custom elements shouldn't add unnecessary motion to common actions.
"Let people cancel motion" by not forcing them to wait for animations to complete before proceeding, especially for repeated interactions.
// ✅ Allow immediate tap, don't block on animation
Button("Next") {
withAnimation(.easeOut(duration: 0.2)) {
showNext = true
}
}
// User can tap again immediately, not forced to wait
SwiftUI provides animation capabilities; WatchKit offers WKInterfaceImage for layout animations and sequences.
Advantages:
Usage:
Label("Settings", systemImage: "gear")
Image(systemName: "star.fill")
.font(.title) // Scales with text size
Key design principles:
Simplification & Recognition: Create "recognizable, highly simplified design[s]" to avoid confusion. Icons work best with familiar visual metaphors directly connected to their actions or content.
Visual Consistency: Maintain uniform:
Weight Matching: Align interface icon weights with adjacent text for consistent emphasis unless deliberately emphasizing one element.
Optical Alignment: Asymmetric icons may need padding adjustments for optical centering rather than geometric centering, particularly when visual weight concentrates on one area.
Vector formats required: Use PDF or SVG for custom interface icons to enable automatic scaling across display resolutions. PNG requires multiple versions for each icon.
Selected states: System components (toolbars, tab bars, buttons) automatically handle selected appearances—custom versions aren't necessary.
From WWDC25: "A pencil might suggest annotate, and a checkmark can look like confirm—making actions like Select or Edit easy to misread. When there's no clear shorthand, a text label is always the better choice."
Use icons when:
Use text when:
Always provide alternative text labels enabling VoiceOver descriptions:
Image(systemName: "star.fill")
.accessibilityLabel("Favorite")
Consistency and Familiarity: "People expect most gestures to work the same regardless of their current context." Standard gestures like tap, swipe, and drag should perform their expected functions across platforms.
Responsive Feedback: "Handle gestures as responsively as possible" and provide immediate feedback during gesture performance so users can predict outcomes.
Basic gestures supported across all platforms (though precise movements vary by device):
Minimum touch target sizes:
| Platform | Minimum Size | Spacing |
|---|---|---|
| iOS/iPadOS | 44x44 points | 12-24pt padding |
| macOS | Varies by control | System spacing |
| watchOS | System controls | Optimized for small screen |
| tvOS | Large (focus model) | 60pt+ spacing |
// ✅ Adequate touch target
Button("Tap") { }
.frame(minWidth: 44, minHeight: 44)
// ❌ Too small
Button("Tap") { }
.frame(width: 20, height: 20) // Fails accessibility
Custom gestures should only be implemented when necessary and must be:
Warning: Don't replace standard gestures with custom ones. Shortcuts should supplement, not replace, familiar interactions.
Critical: "Give people more than one way to interact with your app." Never assume users can perform specific gestures.
Provide alternatives:
// ✅ Swipe action + button alternative
.swipeActions {
Button("Delete", role: .destructive) {
delete()
}
}
.contextMenu {
Button("Delete", role: .destructive) {
delete()
}
}
Mandatory for: iOS, iPadOS, tvOS Not required for: macOS, visionOS, watchOS
Design principle: "Design a launch screen that's nearly identical to the first screen of your app or game" to avoid jarring visual transitions.
Minimize branding:
No text:
Match appearance:
// Launch screen matches first screen
// Transitions smoothly without flash
Onboarding is a separate experience that follows the launch phase. Provides "a high-level view of your app or game" and can include a splash screen if needed.
When to use: Only when you have meaningful context to communicate to new users.
What onboarding can include:
Timeline:
Device characteristics:
Input methods:
Design patterns:
Content hierarchy:
System integration:
Extends iOS with:
Design considerations:
Characteristics:
Design patterns:
Control sizes:
Constraints:
Design principles:
Characteristics:
Design requirements:
Unique aspects:
Design principles:
Welcoming language requirements:
Avoid phrases with oppressive origins (e.g., "peanut gallery").
Exercise caution with humor — it's subjective and difficult to translate across cultures.
Portraying human diversity:
Avoiding assumptions:
Best practices:
Recognize:
Include:
Prepare software for:
Cultural color awareness:
Use plain language and avoid stereotypes to facilitate smoother localization.
Voice & Tone: Maintain consistent brand personality through written communication.
Visual Elements:
Most critical guidance — restraint:
Defer to content: "Using screen space for an element that does nothing but display a brand asset can mean there's less room for the content people care about."
Logo minimalism: "Resist the temptation to display your logo throughout your app or game unless it's essential for providing context."
Familiar patterns: Maintain standard UI behaviors and component placement even with stylized designs to keep interfaces approachable.
Launch screen caution: Avoid using launch screens for branding since they disappear too quickly; consider onboarding screens instead for brand integration.
Do:
Don't:
Apple trademarks cannot appear in your app name or images—consult Apple's official trademark guidelines.
Symptom: App Store rejection for accessibility violations, or colors don't meet WCAG standards.
Diagnosis:
Solution:
// ❌ PROBLEM: Custom gray fails contrast
Text("Label").foregroundStyle(.gray) // May fail 4.5:1 requirement
// ✅ SOLUTION 1: Use semantic colors (automatic compliance)
Text("Label").foregroundStyle(.secondary)
// ✅ SOLUTION 2: Use darker custom color with verified contrast
Text("Label").foregroundStyle(Color(red: 0.25, green: 0.25, blue: 0.25))
// This achieves ~8:1 contrast on white background (WCAG AAA)
Symptom: Users report difficult tapping, App Store accessibility rejection.
Diagnosis:
// Check button size
Button("Tap") { }
.frame(width: 30, height: 30) // ❌ Too small
Solution:
// ✅ Expand touch target to minimum 44x44
Button("Tap") { }
.frame(minWidth: 44, minHeight: 44)
// ✅ Alternative: Add padding
Button("Tap") { }
.padding() // System adds appropriate padding
Symptom: Colors look wrong in Dark Mode, insufficient contrast.
Diagnosis:
Solution:
// ❌ PROBLEM: Hardcoded white text
Text("Label").foregroundStyle(.white)
// Invisible in Light Mode
// ✅ SOLUTION: Semantic color
Text("Label").foregroundStyle(.primary)
// Black in Light, white in Dark
// ✅ ALTERNATIVE: Asset catalog color with variants
Text("Label").foregroundStyle(Color("BrandText"))
// Define in Assets.xcassets with Light/Dark variants
Symptom: Text hard to read, especially at small sizes or in bright lighting.
Diagnosis:
Text("Headline")
.font(.system(size: 17, weight: .ultralight)) // ❌ Too light
Solution:
// ✅ Use Regular minimum
Text("Headline")
.font(.system(size: 17, weight: .regular))
// ✅ Better: Use system text styles
Text("Headline")
.font(.headline) // Automatically uses appropriate weight
Symptom: Text doesn't scale when user increases text size in Settings.
Diagnosis:
// ❌ Fixed size doesn't scale
Text("Label").font(.system(size: 17))
Solution:
// ✅ Use text styles for automatic scaling
Text("Label").font(.body)
// ✅ Custom font with scaling
Text("Label").font(.custom("CustomFont", size: 17, relativeTo: .body))
Symptom: Users with motion sensitivity experience discomfort.
Diagnosis:
Solution:
// ✅ Check Reduce Motion setting
@Environment(\.accessibilityReduceMotion) var reduceMotion
var body: some View {
content
.animation(reduceMotion ? nil : .spring(), value: isExpanded)
}
// ✅ Alternative: Simpler animation
.animation(reduceMotion ? .linear(duration: 0.1) : .spring(), value: isExpanded)
Symptom: VoiceOver announces unhelpful information like "Button" instead of action.
Diagnosis:
// ❌ Image button without label
Button {
share()
} label: {
Image(systemName: "square.and.arrow.up")
}
// VoiceOver says: "Button"
Solution:
// ✅ Add accessibility label
Button {
share()
} label: {
Image(systemName: "square.and.arrow.up")
}
.accessibilityLabel("Share")
// VoiceOver says: "Share, Button"
Symptom: Colorblind users can't distinguish status.
Diagnosis:
// ❌ Only color indicates state
Circle()
.fill(isComplete ? .green : .red)
Solution:
// ✅ Use shape + color + text
HStack {
Image(systemName: isComplete ? "checkmark.circle.fill" : "xmark.circle.fill")
Text(isComplete ? "Complete" : "Incomplete")
}
.foregroundStyle(isComplete ? .green : .red)
Symptom: App Store rejects launch screen with logo or text.
Diagnosis:
Solution:
// ❌ Launch screen with logo (rejected)
// Launch.storyboard contains app logo
// ✅ Launch screen matches first screen (approved)
// Launch.storyboard shows same background/layout as first screen
// No text, no logos, minimal branding
// Move branding to onboarding screen instead
Symptom: Users confused by app-specific dark mode setting, double settings.
Diagnosis:
Solution:
// ❌ App-specific appearance toggle
.preferredColorScheme(userPreference == .dark ? .dark : .light)
// ✅ Respect system preference
// Remove custom toggle, use system preference
// Let iOS Settings control appearance
WWDC25-356: "Get to know the new design system"
WWDC19-808: "What's New in iOS Design"
hig — Quick decisions, checklists, design review pressure scenariosliquid-glass — iOS 26 material design system implementationliquid-glass-ref — iOS 26 app-wide adoption guideswiftui-layout-ref — Layout implementation detailsaccessibility-diag — Accessibility troubleshooting workflowsLast Updated: Based on Apple HIG (2024-2025), WWDC25-356, WWDC19-808 Skill Type: Reference (Comprehensive guide with code examples)