# Swiftui Components

> SwiftUI component expert for building reusable views, custom modifiers, and view compositions. Use when creating new SwiftUI views or refactoring UI code.

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

---


# SwiftUI Components

## Instructions
1. Analyze the required component functionality
2. Check existing components for reuse
3. Apply project styling conventions
4. Ensure accessibility compliance
5. Add preview providers

## Component Patterns

### View with ViewModel
```swift
import SwiftUI

struct FeatureView: View {
    @State private var viewModel = FeatureViewModel()

    var body: some View {
        NavigationStack {
            content
                .navigationTitle("Feature")
                .task { await viewModel.load() }
        }
    }

    @ViewBuilder
    private var content: some View {
        if viewModel.isLoading {
            ProgressView()
        } else {
            List(viewModel.items) { item in
                ItemRow(item: item)
            }
        }
    }
}

#Preview {
    FeatureView()
}
```

### @Observable ViewModel
```swift
import Foundation

@Observable
final class FeatureViewModel {
    var items: [Item] = []
    var isLoading = false
    var error: Error?

    private let service: ItemServiceProtocol

    init(service: ItemServiceProtocol = ItemService()) {
        self.service = service
    }

    func load() async {
        isLoading = true
        defer { isLoading = false }

        do {
            items = try await service.fetchItems()
        } catch {
            self.error = error
        }
    }
}
```

### Custom View Modifier
```swift
struct CardModifier: ViewModifier {
    func body(content: Content) -> some View {
        content
            .padding()
            .background(.background)
            .clipShape(RoundedRectangle(cornerRadius: 12))
            .shadow(radius: 2)
    }
}

extension View {
    func card() -> some View {
        modifier(CardModifier())
    }
}
```

### Reusable Button Style
```swift
struct PrimaryButtonStyle: ButtonStyle {
    func makeBody(configuration: Configuration) -> some View {
        configuration.label
            .font(.headline)
            .foregroundStyle(.white)
            .frame(maxWidth: .infinity)
            .padding()
            .background(configuration.isPressed ? Color.accentColor.opacity(0.8) : Color.accentColor)
            .clipShape(RoundedRectangle(cornerRadius: 12))
    }
}

extension ButtonStyle where Self == PrimaryButtonStyle {
    static var primary: PrimaryButtonStyle { PrimaryButtonStyle() }
}
```

## Best Practices
- Extract views when they exceed 100 lines
- Use `@ViewBuilder` for conditional content
- Prefer composition over inheritance
- Always add accessibility labels
- Test on multiple device sizes

