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, reviewing component architecture, or writing snapshot and unit tests for components.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "swiftui-style-driven-components" with this command: npx skills add ahmadbrkt/swiftui-style-driven-components-skill/ahmadbrkt-swiftui-style-driven-components-skill-swiftui-style-driven-components

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

  1. Before creating a new component, verify it needs 2+ meaningfully different styles. If not, skip the style protocol.
  2. Follow Apple's patterns (ButtonStyle, LabelStyle) as the gold standard.
  3. Use nested type-erased views in configuration (like LabelStyleConfiguration.Title).
  4. Never expose configuration initializers as public.
  5. Wrap style.makeBody in AnyView for type erasure.
  6. Use DynamicProperty for style protocols, not Sendable.
  7. Read styles from environment using existential type (any [Component]Style).

Core Architecture Principles

  • Protocol: [Component]Style — defines HOW to render
  • Configuration: [Component]StyleConfiguration — contains WHAT to render
  • 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?

  1. Needs multiple styles? → If no, skip style protocol
  2. Create structure → See references/component-structure.md
  3. Define protocol → See references/style-protocol.md
  4. Create configuration → Nested type-erased views pattern
  5. Implement default style → Basic rendering
  6. Add environment key → See references/environment-keys.md
  7. Add convenience accessors → See references/common-patterns.md

Adding a new style?

  1. Create struct conforming to [Component]Style
  2. Implement makeBody(configuration:)
  3. Add convenience accessor (.myStyle)
  4. No component changes needed!

Reviewing component architecture?

  1. Check protocol uses DynamicProperty, @ViewBuilder @MainActor
  2. Verify configuration uses nested type-erased views
  3. Confirm configuration init is internal
  4. Check component wraps style.makeBody in AnyView
  5. Validate environment key uses existential (any [Component]Style)
  6. Ensure new styles don't require component changes

Triage Playbook

  • Creating component file structurereferences/component-structure.md
  • Defining style protocolreferences/style-protocol.md
  • Creating configuration with contentreferences/style-protocol.md
  • Setting up environment keysreferences/environment-keys.md
  • Adding convenience initializersreferences/common-patterns.md
  • Parameterized or adaptive stylesreferences/common-patterns.md
  • Documenting public APIsreferences/documentation.md
  • Using design tokensreferences/design-system.md
  • Writing testsreferences/testing.md
  • Organizing previewsreferences/previews.md
  • Accessibility requirementsreferences/accessibility.md
  • Advanced: state machines, dual protocols, result buildersreferences/advanced-patterns.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 struct Content: View with private let _body: () -> AnyView
  • Configuration Init: internal (not public), @MainActor
  • 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 DynamicProperty for style protocols
  • Use nested type-erased views in configuration
  • Make configuration initializers internal
  • Wrap style.makeBody in AnyView
  • Use design tokens, not magic numbers
  • Provide convenience accessors (.compact, .outlined)

DON'T

  • Add explicit Sendable to style protocols
  • Make configuration initializers public
  • Pass configuration to component initializer
  • Put content properties in style protocol
  • Use style protocol for single-variant components
  • Use AnyView directly as configuration property type
  • Use foregroundColor() (deprecated — use foregroundStyle())
  • Use .cornerRadius() (deprecated — use clipShape())

Review Checklist

Architecture

  • Style protocol uses DynamicProperty
  • makeBody has @ViewBuilder @MainActor
  • Configuration uses nested type-erased views
  • Configuration init is internal
  • Component wraps style.makeBody in AnyView
  • New styles don't require component changes

Environment

  • Uses @Entry macro
  • Stores as existential (any [Component]Style)
  • Modifier uses opaque parameter (some [Component]Style)
  • Default value provided (.automatic)

Quality

  • All public symbols have /// doc comments
  • Component doc comment includes usage example
  • 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

  • references/component-structure.md — File organization, MARK conventions
  • references/documentation.md — Doc comments following Apple conventions
  • references/style-protocol.md — Protocol, configuration, anti-patterns
  • references/environment-keys.md — Environment injection, usage patterns
  • references/common-patterns.md — Convenience inits, parameterized styles, bindings, roles
  • references/advanced-patterns.md — State machines, dual protocols, result builders
  • references/testing.md — Snapshots, config tests, test helpers
  • references/previews.md — Preview structure, stateful helpers, snapshot mapping
  • references/design-system.md — Design tokens, typography, colors
  • references/accessibility.md — Labels, identifiers, Dynamic Type

Philosophy

Style-driven components prioritize:

  1. Extensibility — Add styles without modifying components
  2. Apple Patterns — Follow ButtonStyle, LabelStyle conventions
  3. Simplicity — Skip style protocol for single-variant components
  4. Type Safety — Generic APIs with internal type erasure
  5. Consistency — All components follow same patterns

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

image-gen

Generate AI images from text prompts. Triggers on: "生成图片", "画一张", "AI图", "generate image", "配图", "create picture", "draw", "visualize", "generate an image".

Archived SourceRecently Updated
General

explainer

Create explainer videos with narration and AI-generated visuals. Triggers on: "解说视频", "explainer video", "explain this as a video", "tutorial video", "introduce X (video)", "解释一下XX(视频形式)".

Archived SourceRecently Updated
General

asr

Transcribe audio files to text using local speech recognition. Triggers on: "转录", "transcribe", "语音转文字", "ASR", "识别音频", "把这段音频转成文字".

Archived SourceRecently Updated