Native swiftui
Personal Agent Skills for AI coding agents — install and update with gh skill
npx -y skills add dbmrq/agent-skills --skill native-swiftuiAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
- 0 stars0 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
Build iOS apps that look and behave like native Apple software by preferring highest-level SwiftUI components, system styles, semantic colors, and standard navigation structures. Use when creating or reviewing SwiftUI UI, choosing between custom vs built-in controls, styling buttons and cards, or when the user wants a native iOS look, HIG-aligned layouts, or out-of-the-box SwiftUI APIs instead of custom implementations.
SKILL.md
10.4 KB, ~2.5k tokens by cl100k_base, as published. Nobody here has run it
Native SwiftUI
Produce iOS interfaces that feel native by defaulting to Apple's ready-made SwiftUI components and styles before writing custom views. Custom UI is the exception, not the starting point.
Skill split:
native-swiftui(this skill) — what Apple components and system styles to useswiftui-view-composition— how to structure and refactor large views into reusable piecesswiftui-project-structure— repo folders, packages, targets, MV vs Store layersswiftui-expert-skill— state, performance, concurrency (avdlee/swiftui-agent-skill; install via./scripts/install-all.sh)
Agent workflow
- Check deployment target — use the newest APIs the minimum iOS version supports.
- Pick structure first —
NavigationStack/NavigationSplitView+.inspectorbefore inventing custom chrome. - Pick components second — scan built-in-components.md for a system control that fits.
- Style at the root —
.tint,.buttonStyle,.groupBoxStyleonWindowGroupor screen containers (see styling.md). - Verify native feel — system colors, SF Symbols, Dynamic Type, Dark Mode, accessibility labels.
- Reject custom reimplementations — if Apple ships it, use it.
- Structure large screens — if
bodyis hard to scan, applyswiftui-view-composition(extractViewstructs before custom modifiers).
Golden rules
| Prefer | Avoid |
|---|---|
GroupBox, Form, DisclosureGroup for grouped content | Custom RoundedRectangle + shadow "cards" |
.buttonStyle(.borderedProminent) / .bordered + ButtonRole | Hand-rolled button backgrounds and borders |
Semantic colors (.primary, .secondary, .tint, .teal, .mint) | Hard-coded hex/RGB/Color(red:green:blue:) |
Label, LabeledContent for icon+text rows | Manual HStack of Image + Text |
ContentUnavailableView for empty states | Custom empty-state illustrations |
NavigationStack, NavigationSplitView, .inspector | Custom nav bars, sidebars, detail panes |
ShareLink, ColorPicker, PasteButton, RenameButton | UIKit bridges or bespoke controls |
| SF Symbols | Custom icon assets (unless branding requires) |
@Observable + @State | ObservableObject / @Published in new code |
.task / .task(id:) | onAppear { Task { } } without cancellation |
App structure and navigation
iPhone
NavigationStackfor drill-down flows;navigationDestination(for:)for type-safe pushes.TabViewwith theTabAPI (not deprecatedtabItem)..sheet(item:)for model-driven modals; sheet content owns its actions and callsdismiss().
iPad / macOS
NavigationSplitViewfor sidebar + detail; add.inspectorfor supplementary panels (settings, metadata, tools) instead of a third custom column.- Use size classes and
horizontalSizeClassto adapt compact vs regular layouts. ViewThatFitswhen a row may need to collapse to a column on narrow widths.
NavigationSplitView {
List(selection: $selection) { /* sidebar */ }
} detail: {
DetailView(item: selection)
.inspector(isPresented: $showInspector) {
InspectorPanel()
}
}
Settings and forms
Formfor settings screens and data entry.- Nest
GroupBoxinsideFormor otherGroupBoxviews for logical sections — the system alternates backgrounds per nesting level automatically. DisclosureGroupfor expandable settings sections.LabeledContentfor label/value rows (settings detail, read-only info).
Visual grouping
Use Apple's grouping primitives — they carry correct spacing, materials, and accessibility:
GroupBox("Account") {
LabeledContent("Username") { Text(user.name) }
LabeledContent("Plan") { Text(user.plan) }
}
DisclosureGroup("Advanced") {
Toggle("Analytics", isOn: $analytics)
}
ControlGroupfor related actions (media transport, toolbar-like button clusters).OutlineGroupfor hierarchical tree data in lists.Labeleverywhere icons accompany text (lists, buttons, menus).
Buttons and controls
Apply styles once at a container or app root; do not wrap Button in custom MyButton types.
// App root
ContentView()
.tint(.teal)
.buttonStyle(.borderedProminent)
// Destructive actions
Button(role: .destructive) { delete() } label: {
Label("Delete", systemImage: "trash")
}
// Secondary actions
Button("Cancel", role: .cancel) { dismiss() }
.buttonStyle(.bordered)
- Roles:
.destructivefor delete/remove,.cancelfor dismissive actions. - Prominence:
.borderedProminentfor primary CTA;.borderedor.borderlessfor secondary. Stepper,Gauge,Picker,Toggle,Slider— use as-is; apply.pickerStyle(.segmented)etc. at the group level.ShareLinkfor sharing URLs, text, or images — notUIActivityViewControllerwrappers.
Colors, materials, and typography
- Use semantic styles:
.foregroundStyle(.primary),.foregroundStyle(.secondary),.tint(.mint). - Use system palette names (
.teal,.mint,.indigo,.orange) for accents — they adapt to light/dark and accessibility settings. - Use
foregroundStyle()instead of deprecatedforegroundColor(). - Support Dynamic Type — avoid fixed font sizes for body text; use
.font(.body),.headline, etc. MeshGradientfor decorative backgrounds when a multi-point gradient is needed (iOS 18+); prefer materials (.regularMaterial) for functional surfaces.
State, concurrency, and data
From project-wide Swift guidelines:
@Observablefor shared model state;@Stateto own it in a view;@Bindablefor bindings to injected observables.@MainActoron types that drive UI; keep non-UI work off the main actor.async/awaitwith strict concurrency; actors for shared mutable state.- Storage:
UserDefaults(simple prefs), Keychain (secrets), SwiftData (models), CloudKit (sync) — match the problem, don't invent file formats. Loggerinstead ofprint(); no forced unwraps (!).
Animation and live content
TimelineViewfor clocks, countdowns, or periodic refresh (weather, timers) — notTimer+@Statepolling.PhaseAnimatorfor repeating multi-phase animations (pulse, shimmer) — not manual animation loops.ScenePhasevia@Environment(\.scenePhase)for foreground/background lifecycle in views.
Accessibility and platform
- VoiceOver labels and hints on all interactive elements from the start.
- Dark Mode must work without separate color definitions when using semantic colors.
- Follow Human Interface Guidelines and App Store Review expectations.
- Add Previews to every view; use
#Previewwith varied size classes when layout adapts.
Custom UI — only when necessary
Reach for custom views only after confirming no built-in fits:
| Need | Built-in first |
|---|---|
| Card / panel | GroupBox |
| Empty list | ContentUnavailableView |
| Expandable section | DisclosureGroup |
| Icon + title row | Label / LabeledContent |
| Tree list | OutlineGroup |
| Adaptive H/V layout | ViewThatFits |
| Custom arrangement | Layout protocol (not nested stacks with magic numbers) |
| Drawing / charts | Canvas (not UIViewRepresentable unless required) |
| Map | SwiftUI Map + MapKit |
| Multi-date selection | MultiDatePicker |
| Clipboard paste | PasteButton |
| Inline rename | RenameButton |
| Per-corner radius | UnevenRoundedRectangle |
Full catalog with usage notes: built-in-components.md.
Styling system components
- Set
.buttonStyle,.tint,.toggleStyle,.pickerStyleonWindowGroupor screen root — styles propagate like environment values. - Extend built-in styles with
Button(configuration)/ style-configuration initializers instead of per-button modifier stacks. - Nested
GroupBoxdoes not inherit a custom.groupBoxStylefrom its parent — reapply inside the style'smakeBodyor on each nested box. Prefer the default automatic style unless branding requires custom. - Sheets may not inherit styles from the presenter — reapply styles on sheet content when needed.
Details: styling.md.
Code quality checklist
Before finishing UI work:
- No custom card/button when
GroupBox/.borderedProminentsuffices - No hard-coded RGB/hex colors for standard UI
- Navigation uses
NavigationStackorNavigationSplitView(not legacyNavigationView) - Empty states use
ContentUnavailableView - Icons are SF Symbols with appropriate rendering mode
- Forms and settings use
Form+LabeledContent/DisclosureGroup - Primary actions use
.borderedProminent; destructive userole: .destructive - Styles applied at root, not duplicated on every control
- Previews present; Dynamic Type and Dark Mode spot-checked
- Accessibility labels set on custom-labeled controls
View structure
This skill does not cover refactoring large view bodies. When a screen grows beyond a short, scannable body:
- Extract rows, sections, and states into dedicated
Viewstructs — not extension computed properties - Prefer
List/GroupBoxfor extracted pieces instead of custom card modifiers - See
swiftui-view-compositionfor the full extraction workflow, decision guide, and refactor patterns
Swift and project conventions
- One type per file; feature/domain folders (not global
Views//ViewModels/splits). For repo layout, packages, and architecture layers, seeswiftui-project-structure. // MARK: -sections; protocol conformance in extensions.- Swift Testing over XCTest for new tests; meaningful business-logic coverage.
- Remove stale code after refactors; match patterns already in the project.
- Do not add documentation files unless the user asks.