SwiftUI Expert Skill
Overview
Use this skill to build, review, or improve SwiftUI features with correct state management, optimal view composition, and iOS 26+ Liquid Glass styling. Prioritize native APIs, Apple design guidance, and performance-conscious patterns. This skill focuses on facts and best practices without enforcing specific architectural patterns.
Workflow Decision Tree
1) Review existing SwiftUI code
- First, consult
references/latest-apis.md to ensure only current, non-deprecated APIs are used
- Check property wrapper usage against the selection guide (see
references/state-management.md)
- Verify view composition follows extraction rules (see
references/view-structure.md)
- Check performance patterns are applied (see
references/performance-patterns.md)
- Verify list patterns use stable identity (see
references/list-patterns.md)
- Check animation patterns for correctness (see
references/animation-basics.md, references/animation-transitions.md)
- Review accessibility: proper grouping, traits, Dynamic Type support (see
references/accessibility-patterns.md)
- Inspect Liquid Glass usage for correctness and consistency (see
references/liquid-glass.md)
- Validate iOS 26+ availability handling with sensible fallbacks
2) Improve existing SwiftUI code
- First, consult
references/latest-apis.md to replace any deprecated APIs with their modern equivalents
- Audit state management for correct wrapper selection (see
references/state-management.md)
- Extract complex views into separate subviews (see
references/view-structure.md)
- Refactor hot paths to minimize redundant state updates (see
references/performance-patterns.md)
- Ensure ForEach uses stable identity (see
references/list-patterns.md)
- Improve animation patterns (use value parameter, proper transitions, see
references/animation-basics.md, references/animation-transitions.md)
- Improve accessibility: use
Button over tap gestures, add @ScaledMetric for Dynamic Type (see references/accessibility-patterns.md)
- Suggest image downsampling when
UIImage(data:) is used (as optional optimization, see references/image-optimization.md)
- Adopt Liquid Glass only when explicitly requested by the user
3) Implement new SwiftUI feature
- First, consult
references/latest-apis.md to use only current, non-deprecated APIs for the target deployment version
- Design data flow first: identify owned vs injected state (see
references/state-management.md)
- Structure views for optimal diffing (extract subviews early, see
references/view-structure.md)
- Keep business logic in services and models for testability (see
references/layout-best-practices.md)
- Use correct animation patterns (implicit vs explicit, transitions, see
references/animation-basics.md, references/animation-transitions.md, references/animation-advanced.md)
- Use
Button for tappable elements, add accessibility grouping and labels (see references/accessibility-patterns.md)
- Apply glass effects after layout/appearance modifiers (see
references/liquid-glass.md)
- Gate iOS 26+ features with
#available and provide fallbacks
Core Guidelines
State Management
@State must be private; use for internal view state
@Binding only when a child needs to modify parent state
@StateObject when view creates the object; @ObservedObject when injected
- iOS 17+: Use
@State with @Observable classes; use @Bindable for injected observables needing bindings
- Use
let for read-only values; var + .onChange() for reactive reads
- Never pass values into
@State or @StateObject — they only accept initial values
- Nested
ObservableObject doesn't propagate changes — pass nested objects directly; @Observable handles nesting fine
View Composition
- Extract complex views into separate subviews for better readability and performance
- Prefer modifiers over conditional views for state changes (maintains view identity)
- Keep view
body simple and pure (no side effects or complex logic)
- Use
@ViewBuilder functions only for small, simple sections
- Prefer
@ViewBuilder let content: Content over closure-based content properties
- Keep business logic in services and models; views should orchestrate UI flow
- Action handlers should reference methods, not contain inline logic
- Views should work in any context (don't assume screen size or presentation style)
- Pass only needed values to views (avoid large "config" or "context" objects)
- Eliminate unnecessary dependencies to reduce update fan-out
- Consider per-item
@Observable state objects in lists to narrow update/dependency scope
- Consider whether frequently-changing values belong in the environment; prefer more local state when it reduces unnecessary view updates
- Check for value changes before assigning state in hot paths
- Avoid redundant state updates in
onReceive, onChange, scroll handlers
- Minimize work in frequently executed code paths
- Use
LazyVStack/LazyHStack for large lists
- Use stable identity for
ForEach (never .indices for dynamic content)
- Ensure constant number of views per
ForEach element
- Avoid inline filtering in
ForEach (prefilter and cache)
- Avoid
AnyView in list rows
- Consider POD views for fast diffing (or wrap expensive views in POD parents)
- Suggest image downsampling when
UIImage(data:) is encountered (as optional optimization)
- Avoid layout thrash (deep hierarchies, excessive
GeometryReader)
- Gate frequent geometry updates by thresholds
- Use
Self._logChanges() or Self._printChanges() to debug unexpected view updates
Shape.path(), visualEffect, Layout, and onGeometryChange closures may run off the main thread — capture values instead of accessing @MainActor state
Animations
- Use
.animation(_:value:) with value parameter (deprecated version without value is too broad)
- Use
withAnimation for event-driven animations (button taps, gestures)
- Prefer transforms (
offset, scale, rotation) over layout changes (frame) for performance
- Transitions require animations outside the conditional structure
- Custom
Animatable implementations must have explicit animatableData (or use @Animatable macro on iOS 26+)
- iOS 26+: Use
@Animatable macro to auto-synthesize animatableData; use @AnimatableIgnored to exclude properties
- Use
.phaseAnimator for multi-step sequences (iOS 17+)
- Use
.keyframeAnimator for precise timing control (iOS 17+)
- Animation completion handlers need
.transaction(value:) for reexecution
- Implicit animations override explicit animations (later in view tree wins)
Accessibility
- Prefer
Button over onTapGesture for tappable elements (free VoiceOver support)
- Use
@ScaledMetric for custom numeric values that should scale with Dynamic Type
- Group related elements with
accessibilityElement(children: .combine) for joined labels
- Provide
accessibilityLabel when default labels are unclear or missing
- Use
accessibilityRepresentation for custom controls that should behave like native ones
Liquid Glass (iOS 26+)
Only adopt when explicitly requested by the user.
- Use native
glassEffect, GlassEffectContainer, and glass button styles
- Wrap multiple glass elements in
GlassEffectContainer
- Apply
.glassEffect() after layout and visual modifiers
- Use
.interactive() only for tappable/focusable elements
- Use
glassEffectID with @Namespace for morphing transitions
Quick Reference
Property Wrapper Selection
| Wrapper | Use When |
|---|
@State | Internal view state (must be private) |
@Binding | Child modifies parent's state |
@StateObject | View owns an ObservableObject |
@ObservedObject | View receives an ObservableObject |
@Bindable | iOS 17+: Injected @Observable needing bindings |
let | Read-only value from parent |
var | Read-only value watched via .onChange() |
Liquid Glass Patterns
swift
1// Basic glass effect with fallback
2if #available(iOS 26, *) {
3 content
4 .padding()
5 .glassEffect(.regular.interactive(), in: .rect(cornerRadius: 16))
6} else {
7 content
8 .padding()
9 .background(.ultraThinMaterial, in: RoundedRectangle(cornerRadius: 16))
10}
11
12// Grouped glass elements
13GlassEffectContainer(spacing: 24) {
14 HStack(spacing: 24) {
15 GlassButton1()
16 GlassButton2()
17 }
18}
19
20// Glass buttons
21Button("Confirm") { }
22 .buttonStyle(.glassProminent)
Review Checklist
Latest APIs (see references/latest-apis.md)
State Management
Sheets & Navigation (see references/sheet-navigation-patterns.md)
View Structure (see references/view-structure.md)
List Patterns (see references/list-patterns.md)
Layout (see references/layout-best-practices.md)
Animations (see references/animation-basics.md, references/animation-transitions.md, references/animation-advanced.md)
Accessibility (see references/accessibility-patterns.md)
Liquid Glass (iOS 26+)
References
references/latest-apis.md - Required reading for all workflows. Version-segmented guide of deprecated-to-modern API transitions (iOS 15+ through iOS 26+)
references/state-management.md - Property wrappers and data flow
references/view-structure.md - View composition, extraction, and container patterns
references/performance-patterns.md - Performance optimization techniques and anti-patterns
references/list-patterns.md - ForEach identity, stability, and list best practices
references/layout-best-practices.md - Layout patterns, context-agnostic views, and testability
references/accessibility-patterns.md - Accessibility traits, grouping, Dynamic Type, and VoiceOver
references/animation-basics.md - Core animation concepts, implicit/explicit animations, timing, performance
references/animation-transitions.md - Transitions, custom transitions, Animatable protocol
references/animation-advanced.md - Transactions, phase/keyframe animations (iOS 17+), completion handlers (iOS 17+), @Animatable macro (iOS 26+)
references/sheet-navigation-patterns.md - Sheet presentation and navigation patterns
references/scroll-patterns.md - ScrollView patterns and programmatic scrolling
references/image-optimization.md - AsyncImage, image downsampling, and optimization
references/liquid-glass.md - iOS 26+ Liquid Glass API
Philosophy
This skill focuses on facts and best practices, not architectural opinions:
- We don't enforce specific architectures (e.g., MVVM, VIPER)
- We do encourage separating business logic for testability
- We optimize for performance and maintainability
- We follow Apple's Human Interface Guidelines and API design patterns