Learn-skills.dev swiftui-style-driven-components
Expert guidance on SwiftUI style-driven components following Apple patterns (ButtonStyle, LabelStyle). Use when: building components with style protocols, implementing configuration patterns, adding environment-based styling, creating extensible component libraries, or reviewing component architecture.
install
source · Clone the upstream repo
git clone https://github.com/NeverSight/learn-skills.dev
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/NeverSight/learn-skills.dev "$T" && mkdir -p ~/.claude/skills && cp -r "$T/data/skills-md/ahmadbrkt/swiftui-style-driven-components-skill/swiftui-style-driven-components" ~/.claude/skills/neversight-learn-skills-dev-swiftui-style-driven-components && rm -rf "$T"
manifest:
data/skills-md/ahmadbrkt/swiftui-style-driven-components-skill/swiftui-style-driven-components/SKILL.mdsource content
SwiftUI Style-Driven Components
Overview
This skill provides expert guidance on building, reviewing, and extending SwiftUI components following the style-driven architecture pattern. This pattern emphasizes extensibility, maintainability, and Apple-style API design, making it ideal for building reusable component libraries.
Agent Behavior Contract
- Before creating a new component, verify it needs 2+ meaningfully different styles. If not, skip the style protocol.
- Follow Apple's patterns (
,ButtonStyle
) as the gold standard.LabelStyle - Use nested type-erased views in configuration (like
).LabelStyleConfiguration.Title - Never expose configuration initializers as
.public - Wrap
instyle.makeBody
for type erasure.AnyView - Use
for style protocols, notDynamicProperty
.Sendable - Read styles from environment using existential type (
).any [Component]Style
Core Architecture Principles
- Protocol:
— defines HOW to render[Component]Style - Configuration:
— contains WHAT to render[Component]StyleConfiguration - Component: Creates configuration internally, delegates rendering to style
- Environment: Enables subtree styling without modifying components
When to Use Style Protocol
Use style protocol when:
- 2+ meaningfully different visual styles needed
- Environment-based style cascading desired
- Building reusable component library
- Styles need environment access (
)@Environment
Skip style protocol when:
- Single visual representation
- Simple, static appearance
- One-off internal component
- No style customization needed
Quick Decision Tree
Building a new component?
- Needs multiple styles? → If no, skip style protocol
- Create structure → See
references/component-structure.md - Define protocol → See
references/style-protocol.md - Create configuration → Nested type-erased views pattern
- Implement default style → Basic rendering
- Add environment key → See
references/environment-keys.md - Add convenience accessors → See
references/common-patterns.md
Adding a new style?
- Create struct conforming to
[Component]Style - Implement
makeBody(configuration:) - Add convenience accessor (
).myStyle - No component changes needed!
Reviewing component architecture?
- Check protocol uses
,DynamicProperty@ViewBuilder @MainActor - Verify configuration uses nested type-erased views
- Confirm configuration init is
internal - Check component wraps
instyle.makeBodyAnyView - Validate environment key uses existential (
)any [Component]Style - Ensure new styles don't require component changes
Triage Playbook
- Creating component file structure →
references/component-structure.md - Defining style protocol →
references/style-protocol.md - Creating configuration with content →
references/style-protocol.md - Setting up environment keys →
references/environment-keys.md - Adding convenience initializers →
references/common-patterns.md - Parameterized or adaptive styles →
references/common-patterns.md - Using design tokens →
references/design-system.md - Writing snapshot tests →
references/testing.md - Organizing previews →
references/previews.md - Accessibility requirements →
references/accessibility.md
Quick Reference
Component Structure
[Component]/ ├── EnvironmentKeys/[Component]StyleKey.swift ├── Styles/ │ ├── [Component]Style.swift │ ├── [Component]StyleConfiguration.swift │ └── Default[Component]Style.swift └── [Component].swift
Pattern Summary
- Style Protocol:
,DynamicProperty@ViewBuilder @MainActor func makeBody - Configuration: Nested
withstruct Content: Viewprivate let _body: () -> AnyView - Configuration Init:
(notinternal
)public - Component Body:
AnyView(style.makeBody(configuration: .init(...))) - Environment Key:
@Entry public var style: any [Component]Style = .automatic - View Modifier:
func style(_ style: some [Component]Style) -> some View
Best Practices
DO
- Use
for style protocolsDynamicProperty - Use nested type-erased views in configuration
- Make configuration initializers
internal - Wrap
instyle.makeBodyAnyView - Use design tokens, not magic numbers
- Provide convenience accessors (
,.compact
).outlined
DON'T
- Add explicit
to protocolsSendable - Make configuration initializers
public - Pass configuration to component initializer
- Put content properties in style protocol
- Use style protocol for single-variant components
- Use
directly as configuration property typeAnyView
Review Checklist
Architecture
- Style protocol uses
DynamicProperty -
hasmakeBody@ViewBuilder @MainActor - Configuration uses nested type-erased views
- Configuration init is
internal - Component wraps
instyle.makeBodyAnyView - New styles don't require component changes
Environment
- Uses
macro@Entry - Stores as existential (
)any [Component]Style - Modifier uses opaque parameter (
)some [Component]Style - Default value provided (
).automatic
Quality
- Previews cover all styles (see
)references/previews.md - Snapshot tests exist (see
)references/testing.md - Accessibility supported (see
)references/accessibility.md - Design tokens used (see
)references/design-system.md
Reference Files
— Creating new component, file organizationreferences/component-structure.md
— Protocol definition, configuration pattern, adding stylesreferences/style-protocol.md
— Environment injection, usage patternsreferences/environment-keys.md
— Convenience initializers/accessors, parameterized stylesreferences/common-patterns.md
— Snapshot tests, test organizationreferences/testing.md
— Preview structure, checklistreferences/previews.md
— Design tokens, typography, colorsreferences/design-system.md
— Labels, identifiers, Dynamic Typereferences/accessibility.md
Philosophy
Style-driven components prioritize:
- Extensibility — Add styles without modifying components
- Apple Patterns — Follow
,ButtonStyle
conventionsLabelStyle - Simplicity — Skip style protocol for single-variant components
- Type Safety — Generic APIs with internal type erasure
- Consistency — All components follow same patterns