git clone https://github.com/ComeOnOliver/skillshub
T=$(mktemp -d) && git clone --depth=1 https://github.com/ComeOnOliver/skillshub "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/pproenca/dot-skills/ios-design" ~/.claude/skills/comeonoliver-skillshub-ios-design && rm -rf "$T"
skills/pproenca/dot-skills/ios-design/SKILL.mdApple SwiftUI iOS Design Best Practices
A builder's guide for implementing Apple-quality iOS interfaces in SwiftUI, grounded in two foundational design texts:
- Ken Kocienda — Creative Selection (empathy for the user, craft in coding, taste in choosing the best solution, demo culture of iterative refinement)
- John Edson — Design Like Apple (systems thinking, the product is the marketing, design out loud, design with conviction)
Contains 62 rules across 8 principle-based categories. Each rule identifies a specific anti-pattern, grounds the fix in a named principle, and provides the correct iOS 26 / Swift 6.2 SwiftUI implementation.
Scope & Relationship to Sibling Skills
This skill is the building and implementation guide — it teaches how to construct new SwiftUI interfaces from scratch using Apple-quality patterns. When loaded alongside
ios-ui-refactor (reviewing/refactoring existing UI), this skill covers the greenfield implementation that ios-ui-refactor later audits. Use this skill for building new screens; use the sibling for evaluating and improving existing ones.
Clinic Architecture Contract (iOS 26 / Swift 6.2)
All guidance in this skill assumes the clinic modular MVVM-C architecture:
- Feature modules import
+Domain
only (neverDesignSystem
, never sibling features)Data - App target is the convergence point and owns
, concrete coordinators, and Route Shell wiringDependencyContainer
stays pure Swift and defines models plus repository,Domain
,*Coordinating
, andErrorRouting
contractsAppError
owns SwiftData/network/sync/retry/background I/O and implements Domain protocolsData- Read/write flow defaults to stale-while-revalidate reads and optimistic queued writes
- ViewModels call repository protocols directly (no default use-case/interactor layer)
When to Apply
Reference these guidelines when:
- Building new SwiftUI views and screens from scratch
- Choosing between semantic colors, system typography, and spacing grids (Edson's Systems Thinking)
- Managing state with @State, @Binding, @Observable, @Environment (Kocienda's Craft)
- Selecting the right component: List vs LazyVStack, Sheet vs FullScreenCover (Kocienda's Taste)
- Composing views with @ViewBuilder, custom modifiers, and value types (Kocienda's Creative Selection)
- Implementing navigation with NavigationStack, TabView, sheets (Edson's Conversation)
- Laying out content with stacks, grids, frames, and adaptive layouts (Edson's Design Out Loud)
- Ensuring VoiceOver, touch targets, Dark Mode, and reduce motion support (Kocienda's Empathy)
- Adding transitions, loading states, and animation polish (Edson's Product Is the Marketing)
Rule Categories by Priority
| Priority | Category | Principle | Impact | Prefix | Rules |
|---|---|---|---|---|---|
| 1 | Empathy in Every Pixel | Kocienda "Empathy" · Edson "Design Is About People" | CRITICAL | | 8 |
| 2 | The Visual System | Edson "Systems Thinking" · Kocienda "Convergence" | CRITICAL | | 8 |
| 3 | Craft: State as Foundation | Kocienda "Craft" | CRITICAL | | 7 |
| 4 | Creative Composition | Kocienda "Creative Selection" | HIGH | | 6 |
| 5 | Taste: The Right Choice | Kocienda "Taste" · Edson "Design with Conviction" | HIGH | | 8 |
| 6 | Navigation as Conversation | Edson "Design Is a Conversation" · Kocienda "The Demo" | HIGH | | 9 |
| 7 | Design Out Loud: Layout | Edson "Design Out Loud" · Kocienda "Intersection" | HIGH | | 8 |
| 8 | The Product Speaks | Edson "Product Is the Marketing" · Kocienda "Demo Culture" | MEDIUM | | 8 |
Quick Reference
1. Empathy in Every Pixel (CRITICAL)
Kocienda: "Empathy — trying to see the world from other people's perspectives." Edson: design begins with the person holding the device.
- Use semantic colors, never hard-coded valuesempathy-semantic-colors
- Support Dark Mode from day oneempathy-dark-mode
- Use foregroundStyle over foregroundColorempathy-foreground-style
- Always respect safe areas for contentempathy-safe-areas
- Add VoiceOver labels to every interactive elementempathy-voiceover-labels
- Ensure 44x44 point minimum touch targetsempathy-touch-targets
- Always provide reduce motion fallbackempathy-reduce-motion
- Constrain text to readable width on iPadempathy-readable-width
2. The Visual System (CRITICAL)
Edson: "Zoom out to see relationships between objects." Kocienda: convergence — many decisions narrowing toward one coherent whole.
- Use system typography styles, never fixed sizessystem-typography
- Establish clear visual hierarchy through size, weight, and colorsystem-visual-hierarchy
- Use a 4pt base unit for all spacingsystem-spacing-grid
- Use material backgrounds for depth and layeringsystem-material-backgrounds
- Use SF Symbols for consistent iconographysystem-sf-symbols
- Apply gradients for visual depth, not decorationsystem-gradients
- Use system standard margins consistentlysystem-standard-margins
- Configure stack alignment and spacing explicitlysystem-stack-config
3. Craft: State as Foundation (CRITICAL)
Kocienda: "Craft — applying skill to achieve a high-quality result."
- Use @State for view-local value typescraft-state-local
- Use @Binding for child view mutationscraft-state-binding
- Use @Environment for shared app-wide datacraft-state-environment
- Use @Observable for model classescraft-state-observable
- Never create state inside the view bodycraft-avoid-body-state
- Minimize state scope to reduce re-renderscraft-minimize-scope
- Use @Bindable for @Observable bindingscraft-state-bindable
4. Creative Composition (HIGH)
Kocienda: "Creative selection — great software is built through composition and recombination."
- Return some View from body, never concrete typescompose-body-some-view
- Use properties to make views configurablecompose-custom-properties
- Apply view modifiers in the correct ordercompose-modifier-order
- Use @ViewBuilder for flexible slot-based compositioncompose-viewbuilder
- Prefer value types for view datacompose-prefer-value-types
- Prefer composition over inheritance for view reusecompose-prefer-composition
5. Taste: The Right Choice (HIGH)
Kocienda: "Taste — refined judgment, the ability to choose the one right solution." Edson: commit to one approach and perfect it.
- Choose List for system features, LazyVStack for custom layoutstaste-list-vs-lazyvstack
- Choose sheet for tasks, fullScreenCover for immersiontaste-sheet-vs-fullscreen
- Choose the right picker style for the data typetaste-picker
- Choose Grid for aligned data, LazyVGrid for scrollable collectionstaste-grid-vs-lazygrid
- Use button styles that match the action's importancetaste-button
- Configure text input with the right keyboard and content typetaste-textfield
- Use alerts only for critical, blocking informationtaste-alerts
- Use confirmation dialogs for contextual multi-choice actionstaste-action-sheets
6. Navigation as Conversation (HIGH)
Edson: "Design is a conversation between the product and the person." Kocienda: demos as conversations about whether the interface speaks clearly.
- Use NavigationStack for programmatic, type-safe navigationconverse-navigationstack
- Organize app sections with TabView for parallel navigationconverse-tabview
- Use item binding for data-driven sheet presentationconverse-sheet-item
- Use environment dismiss for modal closureconverse-dismiss
- Place toolbar items in the correct semantic positionsconverse-toolbar
- Use tab bar for top-level section navigationconverse-tab-bar
- Configure navigation bar to communicate contextconverse-nav-bar
- Design clear navigation hierarchy before writing codeconverse-hierarchy
- Integrate search with the searchable modifierconverse-search
7. Design Out Loud: Layout (HIGH)
Edson: "Design Out Loud — prototype relentlessly until layout feels inevitable." Kocienda: the intersection of technology and liberal arts.
- Use stacks instead of manual positioninglayout-stacks
- Use Spacer for flexible space distributionlayout-spacer
- Use frame() for explicit size constraintslayout-frame-sizing
- Use ZStack for purposeful layered compositionlayout-zstack
- Use Grid for aligned non-scrolling tabular contentlayout-grid
- Use LazyVGrid for scrollable multi-column layoutslayout-lazy-grids
- Use adaptive layouts for different size classeslayout-adaptive
- Show scroll indicators for long scrollable contentlayout-scroll-indicators
8. The Product Speaks (MEDIUM)
Edson: "The product itself is the marketing." Kocienda: every animation and loading state built to survive Steve Jobs' scrutiny.
- Use semantic transitions for appearing viewsproduct-transitions
- Show honest loading states, not indefinite spinnersproduct-loading-states
- Use withAnimation for explicit state-driven animationproduct-with-animation
- Use matchedGeometryEffect for contextual origin transitionsproduct-matched-geometry
- Design list cells with standard layoutsproduct-list-cells
- Use ContentUnavailableView for empty and error statesproduct-content-unavailable
- Use segmented controls for visible, mutually exclusive optionsproduct-segmented
- Use menus for secondary actions without cluttering the interfaceproduct-menus
How to Use
Read individual reference files for detailed explanations and code examples:
- Section definitions - Category structure, principle sources, and impact levels
- Rule template - Template for adding new rules
Reference Files
| File | Description |
|---|---|
| references/_sections.md | Category definitions and principle grounding |
| assets/templates/_template.md | Template for new rules |
| metadata.json | Version and reference information |