SwiftUI View Generator

VerifiedCaution

Generate well-structured SwiftUI views with proper state management (@State, @Binding, @ObservedObject, @StateObject) and macOS-specific patterns.

Sby Skills Guide Bot
DevelopmentIntermediate
3/11/2026
Claude Code
#swiftui#macos#swift#state-management#ui-generation

Recommended for

Automated summary

Generates macOS SwiftUI views with explicit state management (@State, @Binding, @ObservedObject, @StateObject, @EnvironmentObject) from a JSON spec describing the view and its properties.

Strengths

  • Clear input/output schema (view name, type, state properties, optional ViewModel) that makes generation predictable
  • Applies the correct property wrappers and puts the ViewModel on @MainActor with @Published fields
  • Covers macOS-specific patterns: NavigationSplitView, toolbar, searchable, sheet and #Preview blocks
  • Returns multiple files tagged by type (view, viewmodel, model)

Limitations

  • macOS-focused: iOS, watchOS and tvOS patterns are not addressed
  • Relies on ObservableObject/Combine rather than the newer @Observable macro
  • Assumes an existing Xcode project and describes no build or test step to validate generated code
When to use it

Use it to quickly scaffold a new macOS SwiftUI screen or component together with its data flow and previews.

When not to use it

Skip it for iOS/iPadOS-specific code, AppKit architectures, or when you require the @Observable macro and the Observation framework.

Security analysis

Caution
Quality score74/100

The content is an ordinary SwiftUI code-generation reference: property-wrapper examples, view templates, and JSON schemas. There are no destructive commands, no curl|sh-style installs, no obfuscated payloads, and no attempt to exfiltrate credentials or tokens. Risk is limited to the declared tool set: Write/Edit against a caller-supplied project path plus an unused Bash grant, which warrant caution rather than a clean `safe` rating. No prompt-injection or instruction-override attempts were observed in the data.

Findings
  • •Declares Bash in allowed-tools but no instruction in the skill actually uses it; the code-generation workflow only needs Read/Write/Edit/Glob/Grep, so the shell permission is broader than necessary.
  • •Takes an arbitrary `projectPath` and writes Swift files into it (Write/Edit) with no stated guardrails (e.g., path validation, overwrite confirmation), so an agent could clobber existing sources.
  • •Example code calls an undefined `DataService.shared` network/backing service; harmless as sample code, but it encourages wiring views to data services without describing where data comes from.
  • •Declared allowed-tools include Bash, Write, and Edit, which allow arbitrary command execution and file modification; however, the skill content itself contains no bash commands, no network calls, and no destructive operations — tool use is limited to generating/writing Swift source files in the user's project.
How this analysis is made

Examples

New macOS settings screen
Generate a SwiftUI settings screen named PreferencesView for my macOS project at ~/Dev/MyApp, with @State properties for the selected tab, and a view model.
Sidebar list with search
Create a SwiftUI list view called ProjectListView in ~/Dev/MyApp using NavigationSplitView, a @StateObject view model, and a searchable field wired to the view model.
Reusable component
Generate a reusable SwiftUI component named TagChipView for macOS in ~/Dev/MyApp, taking a @Binding for the selected tag and no view model.

name: swiftui-view-generator description: Generate SwiftUI views with proper state management (@State, @Binding, @ObservedObject, @StateObject) and macOS-specific patterns allowed-tools: Read, Write, Edit, Bash, Glob, Grep tags: [swiftui, macos, swift, ui, apple]

swiftui-view-generator

Generate SwiftUI views with proper state management for macOS applications. This skill creates well-structured SwiftUI components using @State, @Binding, @ObservedObject, @StateObject, and @EnvironmentObject property wrappers.

Capabilities

  • Generate SwiftUI views with proper state management
  • Create reusable view components
  • Set up data flow with Combine
  • Implement navigation patterns
  • Generate macOS-specific UI elements
  • Create preference-based layouts
  • Set up environment values
  • Generate preview providers

Input Schema

{
  "type": "object",
  "properties": {
    "projectPath": {
      "type": "string",
      "description": "Path to the Swift project"
    },
    "viewName": {
      "type": "string",
      "description": "Name of the view to generate"
    },
    "viewType": {
      "enum": ["screen", "component", "list", "form", "settings", "sheet"],
      "default": "screen"
    },
    "stateProperties": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "name": { "type": "string" },
          "type": { "type": "string" },
          "wrapper": { "enum": ["State", "Binding", "ObservedObject", "StateObject", "EnvironmentObject"] }
        }
      }
    },
    "includeViewModel": {
      "type": "boolean",
      "default": true
    },
    "macOSSpecific": {
      "type": "boolean",
      "default": true
    }
  },
  "required": ["projectPath", "viewName"]
}

Output Schema

{
  "type": "object",
  "properties": {
    "success": { "type": "boolean" },
    "files": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "path": { "type": "string" },
          "type": { "enum": ["view", "viewmodel", "model"] }
        }
      }
    }
  },
  "required": ["success"]
}

Generated SwiftUI View Example

// ContentView.swift
import SwiftUI

struct ContentView: View {
    @StateObject private var viewModel = ContentViewModel()
    @State private var searchText = ""
    @State private var isShowingSettings = false

    var body: some View {
        NavigationSplitView {
            // Sidebar
            SidebarView(selection: $viewModel.selectedCategory)
        } detail: {
            // Detail view
            if let category = viewModel.selectedCategory {
                CategoryDetailView(category: category)
            } else {
                Text("Select a category")
                    .foregroundStyle(.secondary)
            }
        }
        .searchable(text: $searchText, prompt: "Search items...")
        .onChange(of: searchText) { _, newValue in
            viewModel.search(query: newValue)
        }
        .toolbar {
            ToolbarItemGroup {
                Button(action: viewModel.refresh) {
                    Label("Refresh", systemImage: "arrow.clockwise")
                }

                Button(action: { isShowingSettings = true }) {
                    Label("Settings", systemImage: "gear")
                }
            }
        }
        .sheet(isPresented: $isShowingSettings) {
            SettingsView()
        }
        .task {
            await viewModel.loadData()
        }
    }
}

// MARK: - Preview
#Preview {
    ContentView()
}

#Preview("With Data") {
    ContentView()
        .environmentObject(PreviewData.sampleViewModel)
}

ViewModel

// ContentViewModel.swift
import SwiftUI
import Combine

@MainActor
class ContentViewModel: ObservableObject {
    @Published var items: [Item] = []
    @Published var selectedCategory: Category?
    @Published var isLoading = false
    @Published var errorMessage: String?

    private let dataService: DataService
    private var cancellables = Set<AnyCancellable>()

    init(dataService: DataService = .shared) {
        self.dataService = dataService
    }

    func loadData() async {
        isLoading = true
        errorMessage = nil

        do {
            items = try await dataService.fetchItems()
        } catch {
            errorMessage = error.localizedDescription
        }

        isLoading = false
    }

    func search(query: String) {
        // Debounced search implementation
        Task {
            try? await Task.sleep(nanoseconds: 300_000_000)
            // Perform search
        }
    }

    func refresh() {
        Task {
            await loadData()
        }
    }
}

Reusable Component

// ItemRowView.swift
import SwiftUI

struct ItemRowView: View {
    let item: Item
    @Binding var isSelected: Bool
    var onDelete: (() -> Void)?

    var body: some View {
        HStack {
            Image(systemName: item.icon)
                .foregroundStyle(item.color)
                .frame(width: 24, height: 24)

            VStack(alignment: .leading, spacing: 4) {
                Text(item.title)
                    .font(.headline)

                Text(item.subtitle)
                    .font(.subheadline)
                    .foregroundStyle(.secondary)
            }

            Spacer()

            if isSelected {
                Image(systemName: "checkmark")
                    .foregroundStyle(.blue)
            }
        }
        .padding(.vertical, 4)
        .contentShape(Rectangle())
        .onTapGesture {
            isSelected.toggle()
        }
        .contextMenu {
            Button("Edit") { }
            Button("Duplicate") { }
            Divider()
            Button("Delete", role: .destructive) {
                onDelete?()
            }
        }
    }
}

Settings View (macOS)

// SettingsView.swift
import SwiftUI

struct SettingsView: View {
    var body: some View {
        TabView {
            GeneralSettingsView()
                .tabItem {
                    Label("General", systemImage: "gear")
                }

            AppearanceSettingsView()
                .tabItem {
                    Label("Appearance", systemImage: "paintpalette")
                }

            AdvancedSettingsView()
                .tabItem {
                    Label("Advanced", systemImage: "slider.horizontal.3")
                }
        }
        .frame(width: 500, height: 400)
    }
}

struct GeneralSettingsView: View {
    @AppStorage("launchAtLogin") private var launchAtLogin = false
    @AppStorage("checkForUpdates") private var checkForUpdates = true

    var body: some View {
        Form {
            Toggle("Launch at Login", isOn: $launchAtLogin)
            Toggle("Check for Updates Automatically", isOn: $checkForUpdates)
        }
        .formStyle(.grouped)
        .padding()
    }
}

List View with Selection

// ItemListView.swift
import SwiftUI

struct ItemListView: View {
    @ObservedObject var viewModel: ItemListViewModel
    @State private var selection: Set<Item.ID> = []
    @State private var sortOrder = [KeyPathComparator(\Item.name)]

    var body: some View {
        Table(viewModel.items, selection: $selection, sortOrder: $sortOrder) {
            TableColumn("Name", value: \.name)
            TableColumn("Type", value: \.type)
            TableColumn("Modified", value: \.modifiedDate) { item in
                Text(item.modifiedDate, style: .date)
            }
            TableColumn("Size") { item in
                Text(ByteCountFormatter.string(fromByteCount: item.size, countStyle: .file))
            }
            .width(80)
        }
        .onChange(of: sortOrder) { _, newOrder in
            viewModel.sort(by: newOrder)
        }
        .contextMenu(forSelectionType: Item.ID.self) { items in
            Button("Open") { viewModel.open(items) }
            Button("Delete", role: .destructive) { viewModel.delete(items) }
        } primaryAction: { items in
            viewModel.open(items)
        }
    }
}

State Management Patterns

@State - Local state

@State private var isExpanded = false
@State private var selectedTab = 0

@Binding - Two-way binding from parent

@Binding var isPresented: Bool
@Binding var selectedItem: Item?

@StateObject - Owned observable object

@StateObject private var viewModel = MyViewModel()

@ObservedObject - Passed observable object

@ObservedObject var viewModel: MyViewModel

@EnvironmentObject - Shared via environment

@EnvironmentObject var settings: AppSettings

@AppStorage - UserDefaults backed

@AppStorage("username") private var username = ""

Best Practices

  1. Use @StateObject for ownership: When the view creates the object
  2. Use @ObservedObject for injection: When the object is passed in
  3. Keep views small: Extract components
  4. Use previews: Test different states
  5. Mark async operations: Use @MainActor for ViewModels
  6. Handle errors gracefully: Show user-friendly messages

Related Skills

  • macos-entitlements-generator - App capabilities
  • macos-notarization-workflow - Distribution
  • xctest-ui-test-generator - UI testing

Related Agents

  • swiftui-macos-expert - SwiftUI expertise
  • desktop-ux-analyst - UX patterns

From the file to a first result

The download contains exactly the content displayed on this page. This copy may differ from the latest version in the source repository.

View the source and supporting files

This download contains SKILL.md only. Any scripts, references, templates and dependencies are not included. Get the required files from the source, preserving their directory structure, before continuing.

1. Download the file

Download SKILL.md

From the root of a test project, save the file as .skill-downloads/swiftui-view-generator-mmlj2o7o/SKILL.md, or use the command below. This folder is for inspecting the skill before installation.

Command for macOS/Linux or WSL: requires a POSIX shell and curl. On Windows without WSL, use the download button and create the folder manually.

mkdir -p '.skill-downloads/swiftui-view-generator-mmlj2o7o' && curl --fail --show-error --location 'https://skills-guides.com/api/skills/swiftui-view-generator-mmlj2o7o/download' --output '.skill-downloads/swiftui-view-generator-mmlj2o7o/SKILL.md.part' && mv '.skill-downloads/swiftui-view-generator-mmlj2o7o/SKILL.md.part' '.skill-downloads/swiftui-view-generator-mmlj2o7o/SKILL.md'

2. Check prerequisites

Read SKILL.md before using it. If it references scripts or external services, inspect them and prepare the required access in your test environment.

Tools declared by the author (check availability in your agent): Read, Write, Edit, Bash, Glob, Grep

No recognized prerequisites section in this file. This does not mean it is self-contained: libraries, tools and access requirements may be mentioned elsewhere in the content or source repository.

The platforms on this page are catalog indications. The paths below follow tool documentation; they do not prove this skill has been run in those tools. No minimum tool version is confirmed for this listing.

3. Load the skill

After inspection, copy the complete folder into your project using one of the commands below, then open a new tool session. The command stops if a folder with the same name already exists: compare the files before replacing it.

Claude Code
test -f '.skill-downloads/swiftui-view-generator-mmlj2o7o/SKILL.md' && test -s '.skill-downloads/swiftui-view-generator-mmlj2o7o/SKILL.md' && mkdir -p '.claude/skills' && test ! -e '.claude/skills/swiftui-view-generator' && cp -R '.skill-downloads/swiftui-view-generator-mmlj2o7o' '.claude/skills/swiftui-view-generator'

OpenSkills

OpenSkills must already be installed. The local install/read procedure is checked with OpenSkills 1.5.0, which requires Node.js ≥ 20.6.0. Catalog slugs are not resolved automatically.

Official OpenSkills installation
openskills install './.skill-downloads/swiftui-view-generator-mmlj2o7o'

openskills read 'swiftui-view-generator-mmlj2o7o'

Reading should display the installed file content and its base directory. It does not run the skill or install its dependencies.

For an agent that reads AGENTS.md, then sync the index. This command changes AGENTS.md: review the diff before using it.

openskills sync

Manual method or another tool: attach SKILL.md to a conversation, or open it in an agent that can read files. Include any required supporting resources. No universal folder is recognized by every tool.

4. Try a first task

Use a short, synthetic input: an API endpoint, a small document or an interface brief. In a new conversation, attach the file or give the agent its path, then adapt this request:

Read .skill-downloads/swiftui-view-generator-mmlj2o7o/SKILL.md and apply its instructions to this example: [describe a test input]. Identify any missing files, dependencies or access. Produce the result requested by the skill without inventing data or running unreviewed scripts.

Expected result: output matching the skill instructions, or a precise list of missing prerequisites. A read confirmation alone does not validate a first use. If an external resource is unavailable, that path remains untested.

Related skills