agentsclimarketplace

Swiftui component

Skill jeremieb/swift-unit-test-instructions/skills/swiftui-component

A reusable framework of Claude Code instructions for Swift, SwiftUI, and UIKit projects.

Install
npx -y skills add jeremieb/swift-unit-test-instructions --skill swiftui-component

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 5 stars5 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Creates SwiftUI views and screens following MVVM with thin view layers, ViewModel extraction, previews, accessibility support, and loading/error states. Use when user says "create a SwiftUI view", "build a screen", "add a new view", "create a component", "build the UI for", "add a SwiftUI screen", or "make a new SwiftUI page".

SKILL.md

6.5 KB, as published. Nobody here has run it

SwiftUI Component Creator

Instructions

Step 1: Clarify Requirements

Ask if not already provided:

  • What does the view display? (list, detail, form, modal, etc.)
  • What user interactions does it support? (tap, swipe, input, navigation)
  • What data does it need? (local state, fetched from API, passed in)
  • Any navigation behavior? (NavigationLink, sheet, fullScreenCover)
  • Min iOS version? (affects @Observable vs ObservableObject)

Step 2: Choose the State Pattern

iOS TargetPattern
iOS 17+@Observable macro on ViewModel, @State private var viewModel in View
iOS 16 and belowObservableObject + @Published, @StateObject in View

Step 3: Generate the Files

Always generate two files: one View, one ViewModel.

View template (iOS 17+ / @Observable):

// Features/[Name]/[Name]View.swift
import SwiftUI

struct [Name]View: View {
    @State private var viewModel: [Name]ViewModel

    init(viewModel: [Name]ViewModel = [Name]ViewModel()) {
        _viewModel = State(initialValue: viewModel)
    }

    var body: some View {
        content
            .task { await viewModel.onAppear() }
            .alert("Error", isPresented: .constant(viewModel.error != nil)) {
                Button("OK") { viewModel.dismissError() }
            } message: {
                Text(viewModel.error?.localizedDescription ?? "")
            }
    }

    @ViewBuilder
    private var content: some View {
        if viewModel.isLoading {
            ProgressView()
        } else {
            mainContent
        }
    }

    private var mainContent: some View {
        // Primary UI here
        Text(viewModel.title)
            .accessibilityLabel(viewModel.title)
    }
}

#Preview {
    [Name]View(viewModel: [Name]ViewModel())
}

View template (iOS 16 / ObservableObject):

// Features/[Name]/[Name]View.swift
import SwiftUI

struct [Name]View: View {
    @StateObject private var viewModel: [Name]ViewModel

    init(viewModel: [Name]ViewModel = [Name]ViewModel()) {
        _viewModel = StateObject(wrappedValue: viewModel)
    }

    var body: some View {
        // same structure as above
    }
}

ViewModel template (iOS 17+ / @Observable):

// Features/[Name]/[Name]ViewModel.swift
import Foundation
import Observation

@MainActor
@Observable
final class [Name]ViewModel {
    // MARK: - Output State
    private(set) var isLoading = false
    private(set) var title: String = ""
    private(set) var error: Error?

    // MARK: - Dependencies
    private let service: [Service]Protocol

    init(service: [Service]Protocol = [Service]()) {
        self.service = service
    }

    // MARK: - Actions
    func onAppear() async {
        isLoading = true
        defer { isLoading = false }
        do {
            title = try await service.fetchTitle()
        } catch {
            self.error = error
        }
    }

    func dismissError() {
        error = nil
    }
}

ViewModel template (iOS 16 / ObservableObject):

// Features/[Name]/[Name]ViewModel.swift
import Foundation

@MainActor
final class [Name]ViewModel: ObservableObject {
    @Published private(set) var isLoading = false
    @Published private(set) var title: String = ""
    @Published private(set) var error: Error?

    private let service: [Service]Protocol

    init(service: [Service]Protocol = [Service]()) {
        self.service = service
    }

    func onAppear() async {
        isLoading = true
        defer { isLoading = false }
        do {
            title = try await service.fetchTitle()
        } catch {
            self.error = error
        }
    }

    func dismissError() {
        error = nil
    }
}

Step 4: Quality Checklist

Before finalizing, verify:

  • View has zero business logic — only layout and presentation
  • ViewModel has no import SwiftUI (only Foundation, Observation)
  • All external dependencies are injected via init
  • #Preview compiles with default / mock data
  • Loading state is handled
  • Error state is handled (alert, inline message, or empty state)
  • Interactive elements have .accessibilityLabel where needed
  • Navigation is handled via ViewModel output flags, not inline logic

Step 5: Sub-View Extraction

If the view body grows complex (>50 lines), extract sub-views:

// Inline private sub-view (same file — preferred for small extractions)
private extension [Name]View {
    var headerSection: some View {
        VStack(alignment: .leading) {
            // ...
        }
    }
}

For reusable components, create a separate file in Core/Components/.

Examples

Example 1: List screen

User says: "Create a SwiftUI product list screen that fetches products and shows a loading spinner"

Files generated:

  • ProductListView.swift — list with .task, loading overlay, error alert
  • ProductListViewModel.swift — fetches from ProductRepositoryProtocol, manages loading/error state

Example 2: Detail screen

User says: "Build a profile detail screen showing user name, avatar, bio, and a logout button"

Files generated:

  • ProfileView.swift — avatar (AsyncImage), name, bio, logout button
  • ProfileViewModel.swiftonLogout() action, user state, logout confirmation flag

Example 3: Form / input screen

User says: "Create a settings screen with a toggle for notifications and a text field for display name"

Files generated:

  • SettingsView.swift — Form with Toggle and TextField bound to ViewModel
  • SettingsViewModel.swiftnotificationsEnabled, displayName, save() async action

Troubleshooting

Preview crashes: ViewModel has a real dependency with side effects. Add a static var preview: [Name]ViewModel with a mock service, or make the default init safe for previews.

View body is growing too large: Extract into private @ViewBuilder computed properties or private extension sub-views. If a sub-view needs significant logic, give it its own ViewModel.

State not updating in view: For @Observable, ensure @State is used in the View (not @StateObject). For ObservableObject, ensure @Published is on the property.

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.