Antigravity-awesome-skills swiftui-expert-skill
Write, review, or improve SwiftUI code following best practices for state management, view composition, performance, modern APIs, Swift concurrency, and iOS 26+ Liquid Glass adoption. Use when buil...
install
source · Clone the upstream repo
git clone https://github.com/benjaminasterA/antigravity-awesome-skills
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/benjaminasterA/antigravity-awesome-skills "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/swiftui-expert-skill" ~/.claude/skills/benjaminastera-antigravity-awesome-skills-swiftui-expert-skill && rm -rf "$T"
manifest:
skills/swiftui-expert-skill/SKILL.mdsource content
SwiftUI Expert Skill
Overview
Use this skill to build, review, or improve SwiftUI features with correct state management, modern API usage, Swift concurrency best practices, 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.
When to Use This Skill
Use this skill when:
- Building new SwiftUI features
- Refactoring existing SwiftUI views
- Reviewing SwiftUI code quality
- Adopting modern SwiftUI patterns
- Working with SwiftUI state management
- Implementing iOS 26+ Liquid Glass styling
Workflow Decision Tree
1) Review existing SwiftUI code
- Check property wrapper usage against the selection guide (see
)references/state-management.md - Verify modern API usage (see
)references/modern-apis.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 - 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
- Audit state management for correct wrapper selection (prefer
over@Observable
)ObservableObject - Replace deprecated APIs with modern equivalents (see
)references/modern-apis.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 - Suggest image downsampling when
is used (as optional optimization, seeUIImage(data:)
)references/image-optimization.md - Adopt Liquid Glass only when explicitly requested by the user
3) Implement new SwiftUI feature
- Design data flow first: identify owned vs injected state (see
)references/state-management.md - Use modern APIs (no deprecated modifiers or patterns, see
)references/modern-apis.md - Use
for shared state (with@Observable
if not using default actor isolation)@MainActor - Structure views for optimal diffing (extract subviews early, keep views small, see
)references/view-structure.md - Separate business logic into testable models (see
)references/layout-best-practices.md - Apply glass effects after layout/appearance modifiers (see
)references/liquid-glass.md - Gate iOS 26+ features with
and provide fallbacks#available
Core Guidelines
State Management
- Always prefer
over@Observable
for new codeObservableObject - Mark
classes with@Observable
unless using default actor isolation@MainActor - Always mark
and@State
as@StateObject
(makes dependencies clear)private - Never declare passed values as
or@State
(they only accept initial values)@StateObject - Use
with@State
classes (not@Observable
)@StateObject
only when child needs to modify parent state@Binding
for injected@Bindable
objects needing bindings@Observable- Use
for read-only values;let
+var
for reactive reads.onChange() - Legacy:
for owned@StateObject
;ObservableObject
for injected@ObservedObject - Nested
doesn't work (pass nested objects directly);ObservableObject
handles nesting fine@Observable
Modern APIs
- Use
instead offoregroundStyle()foregroundColor() - Use
instead ofclipShape(.rect(cornerRadius:))cornerRadius() - Use
API instead ofTabtabItem() - Use
instead ofButton
(unless need location/count)onTapGesture() - Use
instead ofNavigationStackNavigationView - Use
for type-safe navigationnavigationDestination(for:) - Use two-parameter or no-parameter
variantonChange() - Use
for rendering SwiftUI viewsImageRenderer - Use
instead of.sheet(item:)
for model-based content.sheet(isPresented:) - Sheets should own their actions and call
internallydismiss() - Use
for programmatic scrolling with stable IDsScrollViewReader - Avoid
for sizingUIScreen.main.bounds - Avoid
when alternatives exist (e.g.,GeometryReader
)containerRelativeFrame()
Swift Best Practices
- Use modern Text formatting (
parameters, not.format
)String(format:) - Use
for user-input filtering (notlocalizedStandardContains()
)contains() - Prefer static member lookup (
vs.blue
)Color.blue - Use
modifier for automatic cancellation of async work.task - Use
for value-dependent tasks.task(id:)
View Composition
- Prefer modifiers over conditional views for state changes (maintains view identity)
- Extract complex views into separate subviews for better readability and performance
- Keep views small for optimal performance
- Keep view
simple and pure (no side effects or complex logic)body - Use
functions only for small, simple sections@ViewBuilder - Prefer
over closure-based content properties@ViewBuilder let content: Content - Separate business logic into testable models (not about enforcing architectures)
- Action handlers should reference methods, not contain inline logic
- Use relative layout over hard-coded constants
- Views should work in any context (don't assume screen size or presentation style)
Performance
- Pass only needed values to views (avoid large "config" or "context" objects)
- Eliminate unnecessary dependencies to reduce update fan-out
- Check for value changes before assigning state in hot paths
- Avoid redundant state updates in
,onReceive
, scroll handlersonChange - Minimize work in frequently executed code paths
- Use
/LazyVStack
for large listsLazyHStack - Use stable identity for
(neverForEach
for dynamic content).indices - Ensure constant number of views per
elementForEach - Avoid inline filtering in
(prefilter and cache)ForEach - Avoid
in list rowsAnyView - Consider POD views for fast diffing (or wrap expensive views in POD parents)
- Suggest image downsampling when
is encountered (as optional optimization)UIImage(data:) - Avoid layout thrash (deep hierarchies, excessive
)GeometryReader - Gate frequent geometry updates by thresholds
- Use
to debug unexpected view updatesSelf._printChanges()
Liquid Glass (iOS 26+)
Only adopt when explicitly requested by the user.
- Use native
,glassEffect
, and glass button stylesGlassEffectContainer - Wrap multiple glass elements in
GlassEffectContainer - Apply
after layout and visual modifiers.glassEffect() - Use
only for tappable/focusable elements.interactive() - Use
withglassEffectID
for morphing transitions@Namespace
Quick Reference
Property Wrapper Selection (Modern)
| Wrapper | Use When |
|---|---|
| Internal view state (must be ), or owned class |
| Child modifies parent's state |
| Injected needing bindings |
| Read-only value from parent |
| Read-only value watched via |
Legacy (Pre-iOS 17):
| Wrapper | Use When |
|---|---|
| View owns an (use with instead) |
| View receives an |
Modern API Replacements
| Deprecated | Modern Alternative |
|---|---|
| |
| |
| API |
| (unless need location/count) |
| |
| or |
| |
| or |
| |
| |
| (for user input) |
Liquid Glass Patterns
// Basic glass effect with fallback if #available(iOS 26, *) { content .padding() .glassEffect(.regular.interactive(), in: .rect(cornerRadius: 16)) } else { content .padding() .background(.ultraThinMaterial, in: RoundedRectangle(cornerRadius: 16)) } // Grouped glass elements GlassEffectContainer(spacing: 24) { HStack(spacing: 24) { GlassButton1() GlassButton2() } } // Glass buttons Button("Confirm") { } .buttonStyle(.glassProminent)
Review Checklist
State Management
- Using
instead of@Observable
for new codeObservableObject -
classes marked with@Observable
(if needed)@MainActor - Using
with@State
classes (not@Observable
)@StateObject -
and@State
properties are@StateObjectprivate - Passed values NOT declared as
or@State@StateObject -
only where child modifies parent state@Binding -
for injected@Bindable
needing bindings@Observable - Nested
avoided (or passed directly to child views)ObservableObject
Modern APIs (see references/modern-apis.md
)
references/modern-apis.md- Using
instead offoregroundStyle()foregroundColor() - Using
instead ofclipShape(.rect(cornerRadius:))cornerRadius() - Using
API instead ofTabtabItem() - Using
instead ofButton
(unless need location/count)onTapGesture() - Using
instead ofNavigationStackNavigationView - Avoiding
UIScreen.main.bounds - Using alternatives to
when possibleGeometryReader - Button images include text labels for accessibility
Sheets & Navigation (see references/sheet-navigation-patterns.md
)
references/sheet-navigation-patterns.md- Using
for model-based sheets.sheet(item:) - Sheets own their actions and dismiss internally
- Using
for type-safe navigationnavigationDestination(for:)
ScrollView (see references/scroll-patterns.md
)
references/scroll-patterns.md- Using
with stable IDs for programmatic scrollingScrollViewReader - Using
instead of initializer parameter.scrollIndicators(.hidden)
Text & Formatting (see references/text-formatting.md
)
references/text-formatting.md- Using modern Text formatting (not
)String(format:) - Using
for search filteringlocalizedStandardContains()
View Structure (see references/view-structure.md
)
references/view-structure.md- Using modifiers instead of conditionals for state changes
- Complex views extracted to separate subviews
- Views kept small for performance
- Container views use
@ViewBuilder let content: Content
Performance (see references/performance-patterns.md
)
references/performance-patterns.md- View
kept simple and pure (no side effects)body - Passing only needed values (not large config objects)
- Eliminating unnecessary dependencies
- State updates check for value changes before assigning
- Hot paths minimize state updates
- No object creation in
body - Heavy computation moved out of
body
List Patterns (see references/list-patterns.md
)
references/list-patterns.md- ForEach uses stable identity (not
).indices - Constant number of views per ForEach element
- No inline filtering in ForEach
- No
in list rowsAnyView
Layout (see references/layout-best-practices.md
)
references/layout-best-practices.md- Avoiding layout thrash (deep hierarchies, excessive GeometryReader)
- Gating frequent geometry updates by thresholds
- Business logic separated into testable models
- Action handlers reference methods (not inline logic)
- Using relative layout (not hard-coded constants)
- Views work in any context (context-agnostic)
Liquid Glass (iOS 26+)
-
with fallback for Liquid Glass#available(iOS 26, *) - Multiple glass views wrapped in
GlassEffectContainer -
applied after layout/appearance modifiers.glassEffect() -
only on user-interactable elements.interactive() - Shapes and tints consistent across related elements
References
- Property wrappers and data flow (preferreferences/state-management.md
)@Observable
- View composition, extraction, and container patternsreferences/view-structure.md
- Performance optimization techniques and anti-patternsreferences/performance-patterns.md
- ForEach identity, stability, and list best practicesreferences/list-patterns.md
- Layout patterns, context-agnostic views, and testabilityreferences/layout-best-practices.md
- Modern API usage and deprecated replacementsreferences/modern-apis.md
- Sheet presentation and navigation patternsreferences/sheet-navigation-patterns.md
- ScrollView patterns and programmatic scrollingreferences/scroll-patterns.md
- Modern text formatting and string operationsreferences/text-formatting.md
- AsyncImage, image downsampling, and optimizationreferences/image-optimization.md
- iOS 26+ Liquid Glass APIreferences/liquid-glass.md
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 prioritize modern APIs over deprecated ones
- We emphasize thread safety with
and@MainActor@Observable - We optimize for performance and maintainability
- We follow Apple's Human Interface Guidelines and API design patterns