ui-patterns
Skill0 starsChanged 7 months agoMITView on GitHub
Best practices and patterns for building SwiftUI views and components. Use when creating or refactoring SwiftUI UI, designing tab architecture, composing screens, or needing component-specific guidance.
5 other projects use a version of this.
Adopted by
Most recently taken up by
- lubusIN/frappe-skillstheir own version, first seen Nov 4, 2026
- poooi/poitheir own version, first seen Oct 8, 2026
- Iteam-company/claude-code-boilerplatestheir own version, first seen May 19, 2026
- Hey-Diga/dotclaudetheir own version, first seen Feb 23, 2026
- patrickserrano/skillsword for word, first seen Jan 17, 2026
Other versions5 projects use a version of this.
Word for word · 1
- patrickserrano/skills★ 13100% same
Edited · 0
None found.
Wrote their own version · 4
- poooi/poi★ 1.8ksame name
- lubusIN/frappe-skills★ 68same name
- Hey-Diga/dotclaude★ 17same name
- Iteam-company/claude-code-boilerplates★ 2same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository8 other files it gives its agents.
- app-store-preflight-skillsSkill
- fastapi-patternsSkill
- frontend-designSkill
- mcp-builderSkill
- code-documentationSkill
- python-testingSkill
- view-refactorSkill
- theme-factorySkill
The file
Show its rules and text
We split this skill into the rules it gives an agent
13 rules. 0 are common, 7 are distinctive, and 6 are very specific to this project.
0
Common
Most of the 4 edited versions we read keep these.
7
Distinctive
This author's own choices. Worth a look.
6
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 18
Add minimal AppTab enum and RouterPath
- Very specific: line 23
Use modern SwiftUI state (@State, @Binding, @Observable, @Environment)
- Distinctive: line 24
Avoid unnecessary view models - prefer MV (Model-View) over MVVM
- Distinctive: line 25
Prefer composition; keep views small and focused
- Very specific: line 26
Use async/await with .task and explicit loading/error states
- Distinctive: line 27
Follow the project's formatter and style guide
- Very specific: line 30
Prefer .sheet(item:) over .sheet(isPresented:) when state represents a selected model
- Very specific: line 31
Avoid if let inside a sheet body
- Distinctive: line 40
Add accessibility labels or identifiers for interactive UI
- Distinctive: line 182
Keep views as pure expressions of state
- Very specific: line 183
Put business logic in services/models injected via @Environment
- Distinctive: line 184
Test services and models, not views
- Distinctive: line 185
Use SwiftUI Previews for visual regression testing
“Common” is measured: kept by at least 6 in 10 of the 4 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
SwiftUI UI Patterns
Quick Start
Existing Project
- Identify the feature and primary interaction model (list, detail, editor, settings, tabbed)
- Find nearby examples in the repo with
rg "TabView\("or similar - Apply local conventions: prefer SwiftUI-native state, keep state local
- Build with small, focused subviews and SwiftUI-native data flow
New Project Scaffolding
- Wire TabView + NavigationStack + sheets
- Add minimal
AppTabenum andRouterPath - Expand route and sheet enums as new screens are added
General Rules
- Use modern SwiftUI state (
@State,@Binding,@Observable,@Environment) - Avoid unnecessary view models - prefer MV (Model-View) over MVVM
- Prefer composition; keep views small and focused
- Use async/await with
.taskand explicit loading/error states - Follow the project's formatter and style guide
Sheets Best Practices
- Prefer
.sheet(item:)over.sheet(isPresented:)when state represents a selected model - Avoid
if letinside a sheet body - Sheets should own their actions and call
dismiss()internally
Workflow for a New SwiftUI View
- Define the view's state and its ownership location
- Identify dependencies to inject via
@Environment - Sketch the view hierarchy and extract repeated parts into subviews
- Implement async loading with
.taskand explicit state enum if needed - Add accessibility labels or identifiers for interactive UI
- Validate with a build and update usage callsites if needed
MV Pattern (Preferred over MVVM)
SwiftUI views should be lightweight state expressions. Avoid ViewModels unless truly necessary.
struct FeedView: View {
@Environment(APIClient.self) private var client
enum ViewState {
case loading
case error(String)
case loaded([Post])
}
@State private var viewState: ViewState = .loading
var body: some View {
NavigationStack {
List {
switch viewState {
case .loading:
ProgressView("Loading...")
case .error(let message):
ErrorView(message: message, retry: { await loadFeed() })
case .loaded(let posts):
ForEach(posts) { post in
PostRow(post: post)
}
}
}
.task { await loadFeed() }
}
}
private func loadFeed() async {
do {
let posts = try await client.getFeed()
viewState = .loaded(posts)
} catch {
viewState = .error(error.localizedDescription)
}
}
}Sheet Patterns
Item-driven sheet (preferred)
@State private var selectedItem: Item?
.sheet(item: $selectedItem) { item in
EditItemSheet(item: item)
}Sheet owns its actions
struct EditItemSheet: View {
@Environment(\.dismiss) private var dismiss
@Environment(Store.self) private var store
let item: Item
@State private var isSaving = false
var body: some View {
VStack {
Button(isSaving ? "Saving..." : "Save") {
Task { await save() }
}
}
}
private func save() async {
isSaving = true
await store.save(item)
dismiss()
}
}App-Level Environment Setup
@main
struct MyApp: App {
@State var client: APIClient = .init()
@State var router: AppRouter = .init()
var body: some Scene {
WindowGroup {
TabView(selection: $router.selectedTab) {
ForEach(AppTab.allCases) { tab in
tab.rootView
.tag(tab)
}
}
.environment(client)
.environment(router)
}
}
}State Management Guidelines
| Wrapper | Use Case |
@State | Local, ephemeral view state |
@Binding | Two-way data flow from parent |
@Observable | Shared state across views (iOS 17+) |
@Environment | Dependency injection, app-wide concerns |
@Query | SwiftData queries directly in views |
Task and onChange Patterns
// React to state changes
.task(id: searchText) {
guard !searchText.isEmpty else { return }
await search(query: searchText)
}
// Respond to state transitions
.onChange(of: isActive, initial: false) {
guard isActive else { return }
Task { await refresh() }
}Why Not MVVM?
SwiftUI was designed without ViewModels in mind:
- Views are structs, lightweight and disposable
@State,@Environment,@Observablehandle all data flow needs- ViewModels add complexity, indirection, and cognitive overhead
- SwiftData's
@Queryworks directly in views
Instead:
- Keep views as pure expressions of state
- Put business logic in services/models injected via
@Environment - Test services and models, not views
- Use SwiftUI Previews for visual regression testing
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

