Skip to content
AI & Agents
Skill

/swiftui-view-refactor

SwiftUI view refactor/review: layout, DI, Observation, view models.

BOOST
From plugin
agent-scripts
7.1k54 skills
Install
$ npx -y skills add steipete/agent-scripts --skill swiftui-view-refactor --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/swiftui-view-refactor

Context preview

The summary Claude sees to decide when to auto-load this skill.

SwiftUI view refactor/review: layout, DI, Observation, view models.

SKILL.md

swiftui-view-refactor.SKILL.md
name: swiftui-view-refactor
description: "SwiftUI view refactor/review: layout, DI, Observation, view models."

SwiftUI View Refactor

_Attribution: copied from @Dimillian’s `Dimillian/Skills` (2025-12-31)._

Overview

Apply a consistent structure and dependency pattern to SwiftUI views, with a focus on ordering, Model-View (MV) patterns, careful view model handling, and correct Observation usage.

Core Guidelines

1) View ordering (top → bottom)

  • Environment
  • `private`/`public` `let`
  • `@State` / other stored properties
  • computed `var` (non-view)
  • `init`
  • `body`
  • computed view builders / other view helpers
  • helper / async functions

2) Prefer MV (Model-View) patterns

  • Default to MV: Views are lightweight state expressions; models/services own business logic.
  • Favor `@State`, `@Environment`, `@Query`, and `task`/`onChange` for orchestration.
  • Inject services and shared models via `@Environment`; keep views small and composable.
  • Split large views into subviews rather than introducing a view model.

3) Split large bodies and view properties

  • If `body` grows beyond a screen or has multiple logical sections, split it into smaller subviews.
  • Extract large computed view properties (`var header: some View { ... }`) into dedicated `View` types when they carry state or complex branching.
  • It's fine to keep related subviews as computed view properties in the same file; extract to a standalone `View` struct only when it structurally makes sense or when reuse is intended.
  • Prefer passing small inputs (data, bindings, callbacks) over reusing the entire parent view state.

Example (extracting a section):

var body: some View {
    VStack(alignment: .leading, spacing: 16) {
        HeaderSection(title: title, isPinned: isPinned)
        DetailsSection(details: details)
        ActionsSection(onSave: onSave, onCancel: onCancel)
    }
}

Example (long body → shorter body + computed views in the same file):

var body: some View {
    List {
        header
        filters
        results
        footer
    }
}

private var header: some View {
    VStack(alignment: .leading, spacing: 6) {
        Text(title).font(.title2)
        Text(subtitle).font(.subheadline)
    }
}

private var filters: some View {
    ScrollView(.horizontal, showsIndicators: false) {
        HStack {
            ForEach(filterOptions, id: \.self) { option in
                FilterChip(option: option, isSelected: option == selectedFilter)
                    .onTapGesture { selectedFilter = option }
            }
        }
    }
}

Example (extracting a complex computed view):

private var header: some View {
    HeaderSection(title: title, subtitle: subtitle, status: status)
}

private struct HeaderSection: View {
    let title: String
    let subtitle: String?
    let status: Status

    var body: some View {
        VStack(alignment: .leading, spacing: 4) {
            Text(title).font(.headline)
            if let subtitle { Text(subtitle).font(.subheadline) }
            StatusBadge(status: status)
        }
    }
}

4) View model handling (only if already present)

  • Do not introduce a view model unless the request or existing code clearly calls for one.
  • If a view model exists, make it non-optional when possible.
  • Pass dependencies to the view via `init`, then pass them into the view model in the view's `init`.
  • Avoid `bootstrapIfNeeded` patterns.

Example (Observation-based):

@State private var viewModel: SomeViewModel

init(dependency: Dependency) {
    _viewModel = State(initialValue: SomeViewModel(dependency: dependency))
}

5) Observation usage

  • For `@Observable` reference types, store them as `@State` in the root view.
  • Pass observables down explicitly as needed; avoid optional state unless required.

Workflow

1) Reorder the view to match the ordering rules. 2) Favor MV: move lightweight orchestration into the view using `@State`, `@Environment`, `@Query`, `task`, and `onChange`. 3) If a view model exists, replace optional view models with a non-optional `@State` view model initialized in `init` by passing dependencies from the view. 4) Confirm Observation usage: `@State` for root `@Observable` view models, no redundant wrappers. 5) Keep behavior intact: do not change layout or business logic unless requested.

Notes

  • Prefer small, explicit helpers over large conditional blocks.
  • Keep computed view builders below `body` and non-view computed vars above `init`.
  • For MV-first guidance and rationale, see `references/mv-patterns.md`.
Read more
Ships withagent-scripts

Shared agent instructions, skills, and small portable helpers for Peter's local workspaces.

Get the whole plugin
Stats
7,208
Stars
617
Forks
Active
Maintenance
Shell
Language
MIT
License
19h ago
Last commit
10mo ago
Created
3h ago
Added

Repo: steipete/agent-scripts

Other skills on agent-scripts.