# Swiftui Expert

> Write, review, or improve SwiftUI code following best practices for state management, view composition, performance, accessibility, and modern APIs. Use when building SwiftUI features, refactoring views, reviewing code quality, or adopting modern SwiftUI patterns.

- Skill: `swiftyjourney/swiftui-expert` (Agent Skill, multi-file: 20 files)
- Install (CLI): `npx skillmds@latest add swiftyjourney/swiftui-expert`
- Raw SKILL.md: https://api.skillmd.com/api/skills/swiftyjourney/swiftui-expert/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Web & Frontend
- Author: SwiftyJourney (https://skillmd.com/u/swiftyjourney)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/swiftyjourney/swiftui-expert

---


# SwiftUI Expert Skill

## Agent Behavior Contract

When this skill is active, follow these rules **strictly**:

1. **Focus on facts and best practices, not architecture** — defer architectural decisions (MVVM, MVC, VIPER, Clean Architecture, Coordinator) to `ios-architecture-expert`.
2. **Always prefer `@Observable` over `ObservableObject`** for new code. Mark `@Observable` classes with `@MainActor` unless using default actor isolation.
3. **Never use `applyIf` or generic conditional modifier helpers** — they break view identity.
4. **Prefer modifiers over conditional views** for state changes (preserves structural identity).
5. **Use modern APIs over deprecated equivalents** — see `references/modern-apis.md`.
6. **Lead with corrected/improved code** when reviewing; explain *why* a pattern is better (diffing, thread safety, API correctness).
7. **Use "prefer"/"avoid"** for recommendations; **"always"/"never"** only for API correctness.
8. **Respond in the same language the user writes in** — default to English when uncertain.
9. **Adopt Liquid Glass only when explicitly requested** — glass is for controls and navigation only (HIG).
10. **Gate iOS 26+ features** with `#available` and provide fallbacks.

---

## Diagnostic Table

| Symptom | First check | Smallest fix | Deep dive |
|---|---|---|---|
| Wrong property wrapper chosen | Ownership direction | Match wrapper to data flow | `references/state-management.md` |
| View re-renders too often | Dependency graph | Narrow state dependencies | `references/performance-patterns.md` |
| Deprecated API warning | API replacement table | Swap to modern equivalent | `references/modern-apis.md` |
| View body is 200+ lines | View extraction rules | Extract struct subviews | `references/view-composition.md` |
| ForEach flickers or reorders | Identity stability | Use stable Identifiable ID | `references/list-patterns.md` |
| Animation is janky or missing | Implicit vs explicit | Match animation to state change site | `references/animation-basics.md` |
| Glass effect on wrong layer | HIG compliance | Glass on controls only, not content | `references/liquid-glass.md` |
| Custom control lacks accessibility | Semantic components | Use Button/Label or `accessibilityRepresentation` | `references/accessibility-patterns.md` |
| Tap/gesture not firing inside a scroll or list | Gesture precedence | Use `highPriorityGesture`/`simultaneousGesture` | `references/gestures.md` |
| Async load leaks, re-fires, or janks the UI | Task lifecycle & isolation | `.task`/`.task(id:)`; offload heavy work with `@concurrent` | `references/data-loading-and-tasks.md` |
| Need a layout stacks/grids can't express | Layout negotiation | Conform to the `Layout` protocol | `references/layout-protocol.md` |
| App body won't compile or state leaks across windows | Scene structure | App body returns `some Scene`; `WindowGroup` is per-window | `references/app-lifecycle-and-scenes.md` |
| Persisting settings or restoring per-scene state | Persistence mechanism | `@AppStorage`/`@SceneStorage`/SwiftData/`PreferenceKey` | `references/data-persistence.md` |

---

## Quick Summary

| Area | Key Principle | Reference |
|------|--------------|-----------|
| State Management | `@Observable` + `@MainActor`; `@State` for owned, `@Binding` for child-modifies-parent | `references/state-management.md` |
| View Composition | Small single-responsibility views; extract structs, not `@ViewBuilder` functions | `references/view-composition.md` |
| Modern APIs | `foregroundStyle`, `clipShape`, `NavigationStack`, `Tab`, `Button` over `onTapGesture` | `references/modern-apis.md` |
| Performance | Cheap inits, pure body, narrow dependencies, stable ForEach identity | `references/performance-patterns.md` |
| Animations | `withAnimation` for events, `.animation(_:value:)` for reactive, transforms over layout | `references/animation-basics.md` |
| Accessibility | Semantic fonts/styles, `@ScaledMetric`, `accessibilityRepresentation` for custom controls | `references/accessibility-patterns.md` |
| Liquid Glass | Controls/navigation only (HIG); `Glass.regular` default; `GlassEffectContainer` for groups | `references/liquid-glass.md` |
| Data Loading | `.task` over `.onAppear{Task{}}`; `.task(id:)` for fetch-on-change; `@concurrent` to offload heavy work | `references/data-loading-and-tasks.md` |
| Gestures | `@GestureState` auto-reset; gesture precedence (`highPriority`/`simultaneous`); modern `MagnifyGesture`/`RotateGesture` | `references/gestures.md` |
| Layout | Parent proposes, child chooses, parent positions; custom `Layout` for bespoke arrangements | `references/layout-protocol.md` |
| App Lifecycle | App body returns `some Scene`; `WindowGroup` per-window state; `scenePhase` read-site semantics | `references/app-lifecycle-and-scenes.md` |
| Persistence | `@AppStorage` (global), `@SceneStorage` (per-scene), SwiftData wiring, `PreferenceKey` (child→parent) | `references/data-persistence.md` |

---

## Quick Reference

### Property Wrapper Selection

| Wrapper | Use When |
|---------|----------|
| `@State` | Internal view state (must be `private`), or owned `@Observable` class |
| `@Binding` | Child modifies parent's state |
| `@Bindable` | Injected `@Observable` needing bindings |
| `let` | Read-only value from parent |
| `var` | Read-only value watched via `.onChange()` |

> Full guide including legacy wrappers: [state-management.md](references/state-management.md)

### Modern API Replacements

| Deprecated | Modern Alternative |
|------------|-------------------|
| `foregroundColor()` | `foregroundStyle()` |
| `cornerRadius()` | `clipShape(.rect(cornerRadius:))` |
| `tabItem()` | `Tab` API (iOS 18+) |
| `onTapGesture()` | `Button` (unless need location/count) |
| `NavigationView` | `NavigationStack` |
| `onChange(of:) { value in }` | `onChange(of:) { old, new in }` or `onChange(of:) { }` |
| `GeometryReader` | `containerRelativeFrame()` or `visualEffect()` |
| `MagnificationGesture` | `MagnifyGesture` |
| `RotationGesture` | `RotateGesture` |

> Full table: [modern-apis.md](references/modern-apis.md)

---

## Workflow Decision Tree

### 1) Review existing SwiftUI code
- Check property wrapper usage -> `references/state-management.md`
- Verify modern API usage -> `references/modern-apis.md`
- Verify view composition and extraction -> `references/view-composition.md`
- Check performance patterns -> `references/performance-patterns.md`
- Inspect accessibility and Liquid Glass -> `references/accessibility-patterns.md`, `references/liquid-glass.md`

### 2) Improve existing SwiftUI code
- Audit state management (prefer `@Observable` over `ObservableObject`) -> `references/state-management.md`
- Replace deprecated APIs -> `references/modern-apis.md`
- Extract complex views into subviews -> `references/view-composition.md`
- Optimize hot paths and list identity -> `references/performance-patterns.md`, `references/list-patterns.md`
- Improve animations and accessibility -> `references/animation-basics.md`, `references/accessibility-patterns.md`

### 3) Implement new SwiftUI feature
- Design data flow first: owned vs injected state -> `references/state-management.md`
- Use modern APIs and `@Observable` -> `references/modern-apis.md`
- Structure views for optimal diffing -> `references/view-composition.md`
- Apply correct animation patterns -> `references/animation-basics.md`, `references/animation-advanced.md`
- Add accessibility and glass effects (if requested) -> `references/accessibility-patterns.md`, `references/liquid-glass.md`

---

## Guardrails

- Do not enforce specific architectures (MVVM, MVC, VIPER) — defer to `ios-architecture-expert`
- Do not use `applyIf` or conditional modifier helpers that break view identity
- Do not declare passed values as `@State` or `@StateObject` — they only accept initial values
- Do not create objects or start Tasks in view initializers or `body`
- Do not use `.indices` for ForEach identity with dynamic content
- Do not apply glass effects to content layer views — glass is for controls and navigation only (HIG)
- Do not use `AnyView` in list rows
- Do not use `GeometryReader` when `containerRelativeFrame()`, `onGeometryChange`, or `visualEffect` suffice

---

## Verification Checklist

When implementing or reviewing SwiftUI code:

1. Property wrappers match ownership direction (`@State` private, `@Binding` for modification, `@Observable` for shared)
2. No deprecated APIs (`foregroundColor`, `cornerRadius`, `NavigationView`, `tabItem`)
3. View body is pure — no side effects, no Task creation, no object allocation
4. Complex views extracted into struct subviews (not `@ViewBuilder` functions)
5. ForEach uses stable `Identifiable` identity (never `.indices`)
6. Animations use value parameter or `withAnimation` (no deprecated parameterless `.animation()`)
7. Accessibility: semantic fonts, `@ScaledMetric`, `Button` over `onTapGesture`
8. Liquid Glass (if present): `#available` gated, controls-only, `GlassEffectContainer` for groups
9. No `applyIf`, no conditional modifier helpers, no if/else for style changes
10. Views work in any context (no hardcoded sizes, no `UIScreen.main.bounds`)

---

## Reference Router

Open the smallest reference that matches the question:

- **State & Data Flow**
  - [state-management.md](references/state-management.md) — property wrappers, data flow, when to use a ViewModel
  - [data-persistence.md](references/data-persistence.md) — `@AppStorage`, `@SceneStorage`, SwiftData wiring, `PreferenceKey`
  - [data-loading-and-tasks.md](references/data-loading-and-tasks.md) — `.task`/`.task(id:)` entry points, `@concurrent` offloading, cancellation
- **View Structure & Layout**
  - [view-composition.md](references/view-composition.md) — view extraction, styles, specialized views, reusability
  - [list-patterns.md](references/list-patterns.md) — ForEach identity, stability, list best practices
  - [layout-protocol.md](references/layout-protocol.md) — layout negotiation, custom `Layout`, alignment guides
- **Modern APIs & Navigation**
  - [modern-apis.md](references/modern-apis.md) — modern API usage and deprecated replacements
  - [navigation-patterns.md](references/navigation-patterns.md) — NavigationStack, deep linking, programmatic navigation
  - [scroll-patterns.md](references/scroll-patterns.md) — ScrollView patterns and programmatic scrolling
  - [text-formatting.md](references/text-formatting.md) — modern text formatting and string operations
- **App Structure**
  - [app-lifecycle-and-scenes.md](references/app-lifecycle-and-scenes.md) — App protocol, scenes, `WindowGroup`, `scenePhase`
- **Performance & Optimization**
  - [performance-patterns.md](references/performance-patterns.md) — optimization techniques and anti-patterns
  - [image-optimization.md](references/image-optimization.md) — AsyncImage, image downsampling
- **Animation & Interaction**
  - [animation-basics.md](references/animation-basics.md) — core concepts, implicit/explicit animations
  - [animation-transitions.md](references/animation-transitions.md) — transitions, custom transitions, Animatable
  - [animation-advanced.md](references/animation-advanced.md) — transactions, phase/keyframe, completion handlers
  - [gestures.md](references/gestures.md) — gesture types, `@GestureState`, composition & precedence
- **Accessibility & Platform**
  - [accessibility-patterns.md](references/accessibility-patterns.md) — semantic styling, adaptive spacing, VoiceOver
  - [liquid-glass.md](references/liquid-glass.md) — iOS 26+ Liquid Glass API and HIG guidance

