Comprehensive review and analysis of SwiftUI interfaces for iOS 17/18/26+ with focus on animations, Liquid Glass design language, Apple Human Interface Guidelines (HIG), accessibility standards, and modern UI/UX patterns.
When to Use This Skill
- Reviewing animations - springs, keyframes, transitions, micro-interactions, liquid glass morphing
- Reviewing SwiftUI code for UI/UX best practices
- Auditing compliance with iOS 26 Liquid Glass design language
- Checking accessibility implementation (VoiceOver, Dynamic Type, Reduce Motion)
- Analyzing navigation, onboarding, tabs, sheets, and modal patterns
- Identifying common UI/UX mistakes and anti-patterns
- Evaluating animation performance and timing
- Providing actionable recommendations for interface improvements
Review Process
Step 1: Gather Context
Before reviewing, collect information about:
- Target iOS version - iOS 17+ for PhaseAnimator/KeyframeAnimator; iOS 26+ for Liquid Glass
- App purpose - Different apps require different animation intensities
- User demographics - Accessibility requirements vary by audience
- Existing design system - Check for design tokens and theming
Step 2: Structural Analysis
Analyze the SwiftUI code structure for:
| Component | Check For |
|---|---|
| Navigation | NavigationStack usage, tab bar implementation, deep linking support |
| State Management | @State, @Binding, @Observable patterns, data flow |
| View Hierarchy | Proper component decomposition, reusability |
| Modifiers | Correct modifier ordering, accessibility modifiers |
| Animations | Spring parameters, timing, transitions, accessibility compliance |
Step 3: Animation Review (NEW)
Animation Quality Checklist
| Aspect | Standard | Check For |
|---|---|---|
| Timing | 100-500ms | Animations not too fast or slow |
| Springs | Used for interactive | response, dampingFraction appropriate |
| Purpose | Communicates change | Not gratuitous or distracting |
| Performance | No frame drops | drawingGroup() for complex views |
| Accessibility | Respects settings | Checks accessibilityReduceMotion |
Spring Animation Standards
Recommended Springs:
// Button press - quick, bouncy
.spring(response: 0.3, dampingFraction: 0.6)
// Modal presentation - smooth, natural
.spring(response: 0.5, dampingFraction: 0.8)
// Card expansion - elegant, controlled
.spring(response: 0.6, dampingFraction: 0.85)
// Subtle hover - minimal, fast
.spring(response: 0.2, dampingFraction: 0.9)
iOS 17+ Presets:
.bouncy- High bounce, playful.smooth- No overshoot, professional.snappy- Quick response
iOS 26+ New APIs (WWDC 2025):
@Animatablemacro - Auto-synthesizesAnimatableconformance for Shapes@AnimatableIgnoredmacro - Excludes properties from animation interpolation.symbolEffect(.drawOn)/.symbolEffect(.drawOff)- SF Symbols 7 stroke-based reveal/dismiss animations (supports.wholeSymbol,.byLayer,.individually).backgroundExtensionEffect()- Blur extension beyond view bounds (for sidebars, inspectors)tabViewBottomAccessory { }- Persistent control above tab bar (gets glass capsule automatically)ToolbarSpacer- Control spacing between toolbar itemsscrollExtensionMode(.underSidebar)- Extend scroll content under sidebar- Sheet morphing:
matchedTransitionSource(id:in:)+navigationTransition(.zoom(sourceID:in:)) - Rich
TextEditorwithAttributedStringbinding andonSelectionChange - Label spacing:
.labelIconToTitleSpacing,.labelReservedIconWidth
Common Animation Issues
| Issue | Severity | Solution |
|---|---|---|
.animation() without value |
High | Use .animation(_:value:) |
| Linear timing for UI | Medium | Use springs for natural feel |
No reduceMotion check |
High | Add @Environment(\.accessibilityReduceMotion) |
| Heavy views in keyframes | High | Use drawingGroup() |
Multiple conflicting withAnimation |
Medium | Consolidate into single block |
| Animation during scroll | Medium | Defer until scroll ends |
Transition Review
Check transitions use:
.asymmetric(insertion:removal:)for directional animations.combined(with:)for multi-property transitions- Appropriate timing that matches gesture direction
Micro-Interactions
Verify:
- Button press has visual feedback (scale, opacity)
- Haptic feedback matches action type (
.success,.error,.selection) - Feedback not excessive or annoying
Step 4: Liquid Glass Compliance (iOS 26+)
Glass Variants (IMPORTANT — only 3 exist):
| Variant | Use Case |
|---|---|
.regular |
Standard navigation elements, toolbars, tabs |
.clear |
Subtle controls over media-rich backgrounds |
.identity |
No effect — for conditional toggling / accessibility |
WARNING: .prominent is NOT a glass variant. Use .buttonStyle(.glassProminent) for prominent buttons.
Appropriate Uses:
- Navigation bars and toolbars
- Tab bars and bottom accessories (use
tabViewBottomAccessoryfor floating bars) - Floating action buttons
- Sheets, popovers, and menus (system applies glass automatically in iOS 26)
- Context-sensitive controls
ToolbarSpacerfor grouping toolbar items
Avoid Liquid Glass For:
- Content layer (lists, tables, media)
- Full-screen backgrounds
- Scrollable content
- Stacked glass layers (glass cannot sample other glass)
- Custom shadows/borders (trust system edge effects)
Glass Morphing Animations:
- Use
GlassEffectContainerfor coordinated morphing - Apply
glassEffectID(_:in:)for morph coordination - Use
glassEffectUnion(id:namespace:)to merge related controls into one glass shape - Use
.bouncyanimation for glass transitions - Wrap state changes in
withAnimation(.bouncy) - Don't use
presentationBackground()on sheets — system handles it
New iOS 26 Layout APIs:
tabViewBottomAccessory { }— persistent control above tab bar (like Now Playing)ToolbarSpacer— control spacing between toolbar itemsscrollExtensionMode(.underSidebar)— extend scroll content under sidebarbackgroundExtensionEffect()— extend/blur content behind sidebars- Sheet morphing:
matchedTransitionSource(id:in:)+navigationTransition(.zoom(sourceID:in:))
Check for proper .glassEffect() usage with #available(iOS 26.0, *) guards.
Step 5: Pattern Validation
Onboarding Patterns
- iOS 18+: Prefer ScrollView with
scrollTargetBehavior(.viewAligned)over TabView - Use
@AppStoragefor tracking completion state - Present using
.fullScreenCoverfor immersive experience - Include skip option and progress indicators
- Animations: Staggered entry with
.delay(), parallax effects
Tab Navigation
- Each tab maintains its own NavigationStack
- State preserved when switching tabs
- Coordinator pattern for complex flows
- iOS 26: Tabs auto-shrink on scroll
- Animations:
matchedGeometryEffectfor tab indicator
Sheets and Modals
- Attach
.sheetto outermost container view - Use
presentationDetentsfor height control (iOS 16+) interactiveDismissDisabled()when dismissal must be controlled- Forms for settings/profiles, fullScreenCover for immersive content
- Animations: Spring presentation with
response: 0.5, dampingFraction: 0.8
Loading States
- Use
.redacted(reason: .placeholder)for skeleton views - Model states with enum (loading, loaded, empty, error)
- ContentUnavailableView for empty states (iOS 17+)
.unredacted()for fixed elements during loading- Animations: Shimmer effect with repeating linear gradient
Counter/Numeric Displays
- Use
.contentTransition(.numericText())for animated counters - Combine with
.sensoryFeedback(.increase, trigger:)for haptics
Permission Request Patterns (App Store Guideline 5.1.1)
Critical: Permission primers (custom alerts before iOS permission dialogs) must NOT have exit/dismiss buttons.
Compliant Pattern:
// OK: Primer with only "Continue" - user must proceed to iOS dialog
.alert("Camera Access", isPresented: $showPrimer) {
Button("Continue") { requestCameraPermission() }
} message: {
Text("We need camera access to scan documents.")
}
Non-Compliant Pattern (App Store Rejection):
// REJECTED: "Not Now" lets user skip the iOS permission dialog
.alert("Camera Access", isPresented: $showPrimer) {
Button("Continue") { requestCameraPermission() }
Button("Not Now", role: .cancel) { dismiss() } // ← VIOLATION
} message: {
Text("We need camera access to scan documents.")
}
Best Practices:
- If showing a primer, user MUST proceed to the actual iOS permission dialog
- No "Skip", "Not Now", "Later", or "Cancel" buttons on pre-permission primers
- After denial, you CAN show an alert with "Open Settings" + "Cancel"
- Consider skipping primers entirely - iOS dialogs show your Info.plist usage descriptions
- Request permissions contextually (when user tries to use the feature), not on app launch
Applies to: Camera, Microphone, Photos, Location, Contacts, Calendars, Speech Recognition, Health, Motion, Bluetooth, Local Network, Tracking (ATT)
Step 6: Accessibility Audit
Required Checks:
| Modifier | Purpose |
|---|---|
.accessibilityLabel() |
Descriptive label for VoiceOver |
.accessibilityHint() |
Action context for users |
.accessibilityElement(children:) |
Group related elements |
.accessibilityHidden() |
Hide decorative elements |
Dynamic Type: Verify text scales with system settings. Avoid fixed font sizes.
Reduce Transparency: Check @Environment(\.accessibilityReduceTransparency) for Liquid Glass fallbacks.
Reduce Motion: Check @Environment(\.accessibilityReduceMotion) and disable/simplify animations.
Color Contrast: Use .primary, .secondary over hardcoded colors.
Step 7: Generate Report
Structure findings as:
## UI/UX Review Summary
### Strengths
- [List positive patterns found]
### Animation Issues
1. **[Issue Name]** - Severity: High/Medium/Low
- Location: `FileName.swift:LineNumber`
- Problem: [Description]
- Recommendation: [Specific fix with code]
### UI/UX Issues
1. **[Issue Name]** - Severity: High/Medium/Low
- Location: `FileName.swift:LineNumber`
- Problem: [Description]
- Recommendation: [Specific fix]
### Recommendations
- [Prioritized list of improvements]
### Code Examples
- [Before/after code snippets]
Quick Reference: Common Issues
| Issue | Severity | Solution |
|---|---|---|
| Permission primer with exit button | Critical | Remove "Not Now"/"Skip" - user must proceed to iOS dialog (Guideline 5.1.1) |
| Liquid Glass on content layer | High | Move to navigation layer only |
| Missing accessibility labels | High | Add .accessibilityLabel() to interactive elements |
No reduceMotion check |
High | Add environment check, simplify animations |
.animation() without value |
High | Use .animation(_:value:) |
| Fixed font sizes | Medium | Use system semantic fonts |
| Stacked glass layers | Medium | Reduce glass layers, add spacing |
| Linear animation for buttons | Medium | Use spring with dampingFraction: 0.6-0.8 |
| No haptic feedback | Low | Add .sensoryFeedback() for important actions |
| TabView for iOS 18+ onboarding | Low | Migrate to ScrollView pattern |
| Sheet attached to button | Low | Move to container view |
Animation API Quick Reference
iOS 17+ Animators
// PhaseAnimator - Multi-step cycling
PhaseAnimator([Phase.a, .b, .c], trigger: value) { phase in
Content().modifier(for: phase)
} animation: { phase in
.spring(response: 0.3)
}
// KeyframeAnimator - Fine-grained control
.keyframeAnimator(initialValue: Values(), trigger: trigger) { content, value in
content.scaleEffect(value.scale)
} keyframes: { _ in
KeyframeTrack(\.scale) {
SpringKeyframe(1.2, duration: 0.2)
SpringKeyframe(1.0, duration: 0.3)
}
}
Transitions
// Combined transition
.transition(.move(edge: .bottom).combined(with: .opacity))
// Asymmetric
.transition(.asymmetric(
insertion: .move(edge: .trailing),
removal: .move(edge: .leading)
))
// iOS 17+
.transition(.blurReplace)
.transition(.push(from: .bottom))
Haptic Feedback (iOS 17+)
.sensoryFeedback(.success, trigger: value)
.sensoryFeedback(.selection, trigger: selection)
.sensoryFeedback(.impact, trigger: collision)
Design Tokens Reference
Recommended spacing scale:
xs: 4pt,sm: 8pt,md: 16pt,lg: 24pt,xl: 32pt
Use semantic colors:
.primary,.secondaryfor text.background,.secondaryBackgroundfor surfaces- System tints for interactive elements
Additional Resources
Reference Files
For detailed patterns and guidelines, consult:
references/animation-guide.md- Comprehensive animation reference with springs, keyframes, transitions, micro-interactions, and performance optimizationreferences/liquid-glass-guide.md- Complete iOS 26 Liquid Glass implementation guide with code examplesreferences/ui-patterns.md- Detailed SwiftUI patterns for navigation, onboarding, forms, loading statesreferences/accessibility-checklist.md- Complete VoiceOver, Dynamic Type, Reduce Motion audit checklist with testing procedures
External Resources
Apple Official:
- Human Interface Guidelines - Motion
- Animating views and transitions
- Applying Liquid Glass to custom views
- WWDC23: Demystify SwiftUI performance
- WWDC18: Designing Fluid Interfaces
- WWDC25: Meet Liquid Glass
Animation Libraries:
- Pow - Delightful SwiftUI effects (Spray, Shake, Shine, Jump, Rise, Spin)
- AnimatedTabBar - Preset tab bar animations
- open-swiftui-animations - Loading, looping, spring examples
- Hero - Elegant transition library
- FlowStack - Hero animations with NavigationStack API
- SkeletonUI - Elegant skeleton loading
Hero Transitions:
- swiftui-hero-animations - matchedGeometryEffect examples
- swiftui-hero-animations-no-transitions - Morphing without transitions
Liquid Glass & iOS 26:
- iOS-26-by-Examples - Comprehensive iOS 26 feature examples
- LiquidGlassReference - Ultimate Swift/SwiftUI reference
- LiquidGlassSwiftUI - Sample Liquid Glass app
Tutorials: