dbmrq/agent-skills/swiftui-view-composition
Claude Code and agent skill by dbmrq/agent-skills
- community
Checking that the SKILL.md file is still in the repository.
Structure and refactor SwiftUI views for readability, reuse, and maintainability by extracting dedicated View structs, ViewModifiers, and layout helpers instead of bloated bodies or extension dumping grounds. Use when breaking down large views, improving screen clarity, creating reusable components, or reviewing SwiftUI architecture and view organization.
Install
npx vskill@latest install dbmrq/agent-skills/swiftui-view-compositionSKILL.md
SwiftUI View Composition
Structure SwiftUI screens so body reads like a high-level overview — not an implementation dump. The goal is clarity and reusability, not minimizing line count.
Skill split:
- `swiftui-view-composition` (this skill) — how to structure and refactor views
- `native-swiftui` — what Apple components and system styles to use
- `swiftui-project-structure` — repo folders, packages, targets, MV vs Store layers
- `swiftui-expert-skill` — state, performance, concurrency (avdlee/swiftui-agent-skill; install via
./scripts/install-all.sh)
Agent workflow
- Scan the view — identify logical clusters (header, row, empty state, toolbar, section).
- Ask the reuse question — "Does this UI have a clear purpose and potential to be reused?" (see Decision guide)
- Extract in order — dedicated
View→ repeated styling as modifier → generic layout helper. - Check native alternatives — before custom card/row styling, consult
native-swiftui(GroupBox,List,LabeledContent). - Add previews — each extracted view gets
#Previewwith its states. - Leave `body` declarative — screen view orchestrates; children render.
The problem: growing view bodies
Large body properties with nested stacks and inline styling are hard to scan, test, and evolve. Adding empty states, loading, and actions makes it worse.
First step when refactoring: identify subjects — self-contained UI clusters that could become their own unit.
Anti-pattern: extensions and computed properties
Moving body chunks into extension computed properties or @ViewBuilder functions only moves code around. It does not improve reusability or maintainability, and the file often grows longer.
When computed properties are OK: tiny, single-use sections with no reuse potential and no performance concern — keep them private and simple.
Prefer separate `struct` views for anything with its own concern, multiple states, or reuse potential. Separate structs also let SwiftUI skip body re-evaluation when inputs are unchanged (see swiftui-expert-skill view-structure guidance).
Cross-file extensions
Splitting a type across files (e.g. NoteStore+Notes.swift for SwiftLint length limits) is fine for stores/models. That is not the same as dumping body into extension computed properties.
Access control: private and private(set) are file-private. Extensions in other files cannot read or assign those members — you get “setter is inaccessible” / “inaccessible due to private”. Widen anything shared across those files to `internal` (omit the keyword). Keep private only for helpers that stay in the defining file.
After splits: xcodegen generate (if used), build, then ./scripts/check.sh and ./scripts/deadcode.sh (see ios-quality-gate).
Three extraction techniques
1. Extract dedicated SwiftUI views
Give each logical UI unit its own View struct with explicit inputs:
Benefits:
- Screen
bodyreads as an outline - Single responsibility per file
- States and previews live in one place
- Reusable on other screens
2. Create reusable view modifiers
When the same modifier chain appears on multiple views, extract it — but prefer system styles first (native-swiftui).
Before creating `cardStyle()`: check whether GroupBox, List + .listStyle, or .buttonStyle already solve it. Custom card modifiers are a last resort for branded design tokens, not default row styling.
Detection workflow: search the codebase for repeated modifier combinations → replace with one modifier → update all call sites.
3. Build generic view extensions
For repeated layout patterns (not full components), use @ViewBuilder extensions:
Trade-off: less explicit than a SectionHeader view, but reduces indentation. Use when the wrapper is purely structural and unlikely to need its own state or previews.
Decision guide
Ask before extracting:
"Does this piece of UI have a clear purpose and potential to be reused?"
| Answer | Action | |
|---|---|---|
| Yes — distinct concern, appears elsewhere, or needs isolated previews | New View struct (or ViewModifier for repeated styling) | |
| Maybe — used once now but likely again | Extract View; move to shared folder when second use appears | |
| No — one-off, trivial, tightly coupled to parent | Keep inline or use a small private computed property |
Extraction priority
- Rows and cells (
ArticleRow,SettingsToggleRow) - Empty / loading / error states (often
ContentUnavailableView— seenative-swiftui) - Section headers and toolbars
- Repeated styling → modifier (after checking system alternatives)
- Layout shells → generic extension
Rule of three (abstraction guard)
Promote a view to a shared, generic primitive only after three concrete uses with the same behavior. Before that, keep it feature-local — screen-specific APIs are fine; do not invent a 12-parameter “configurable” view to force reuse.
Configuration objects (avoid long initializers)
When a view would take roughly four or more related parameters — especially mixed data, bindings, and action closures — wrap them in a dedicated configuration (or actions) struct and pass that instead of a flat parameter list.
Keep configuration types feature-local and one primary type per file. Prefer small, named bags (…Configuration, …Actions) over generic “options” dictionaries.
Display-mode sibling views
Do not branch compact/comfortable (or similar display modes) throughout a single body. Create separate views for each mode and toggle at the parent; share metrics/constants in a layout/chrome enum so mode switches stay visually stable.
Refactor walkthrough
Before — monolithic list with inline row styling:
After — composed, native-aligned:
Changes: extracted row, List instead of manual card stacks, navigation title instead of inline header (or use .sectionHeader if staying in VStack).
More patterns: extraction-patterns.md.
File and folder conventions
- One primary type per file; name the file after the type (
ArticleRow.swift,ItemRowActions.swift). - Co-locate by feature —
Articles/ArticleListView.swift,Articles/ArticleRow.swift— not globalViews/dumps. For repo-level layout (packages, targets,Navigation/, when to add a Store), see `swiftui-project-structure`. - Within a feature, use semantic subfolders when the file count grows (e.g.
Editor/Row/,Editor/Chrome/,Editor/Layout/) so related types stay findable. - Shared primitives — only after rule-of-three; e.g.
DesignSystem/ElevatedSurface.swiftor a small Swift package. - `// MARK: -` for properties, body, helpers; protocol conformance in extensions.
Screen vs component views
| Type | Role | API shape | |
|---|---|---|---|
| Screen / orchestrator | Wires navigation, state, and child views | Owns @State, fetches data, composes children | |
| Component | Renders one UI unit | let inputs; callbacks for actions (onTap, onDelete) | |
| Primitive | App-wide design atom | Minimal, stateless, generic |
Do not force screen-specific orchestrators into generic shared components — give them a name and a rich, local API.
Previews
Every extracted view gets previews for its meaningful states:
Use @Previewable for dynamic preview state when needed.
Checklist
Before finishing a refactor:
This is the start of the file. Read the full SKILL.md on GitHub.
Security
- Security scanPassed, 95 of 100Pattern checks on the skill's files.
- Model reviewPassed
Quality evaluation
- Task evaluationNot runNo evaluation yet. Run one in Skill Studio.
Source
- SKILL.md in the repositoryCheckingskills/swiftui-view-composition/SKILL.md
Popularity
- 7-day trend score
- 5
Not refreshed yet.
Works with
Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.
- Claude Code
- Cursor
- GitHub Copilot
- Windsurf
- Codex
- Gemini CLI
- Cline
- Amp
- Roo Code
- Goose
- Continue
- Kilo Code
- Junie
- Trae
- OpenHands
- Qwen Code
- AI Agent
- Tabnine Chat
- Sourcegraph Cody
- Amazon Q
- Firebase Genkit
- Sweep
- Devin
- Phind
- Mentat
- Claude Desktop
- Aider
- GPT Pilot
- Plandex
- bolt.new
- v0
- Replit Agent
- Anse
- TypingMind
- BetterChatGPT
- LibreChat
- Warp AI
- Pieces
- Fig AI
Embed badge
[](https://verified-skill.com/skills/dbmrq/agent-skills/swiftui-view-composition)