Skip to main content
The Composable Architecture was designed with SwiftUI in mind and provides seamless integration with SwiftUI’s declarative view system.

Store in SwiftUI Views

The primary way to integrate TCA with SwiftUI is through the Store type, which can be observed directly in your views.

Basic View Integration

Pass stores to your SwiftUI views and observe state changes:

Using @Bindable (iOS 17+)

For iOS 17 and later, use SwiftUI’s @Bindable to create bindings:

Using Perception.Bindable (iOS 13-16)

For pre-iOS 17, use the Perception framework’s @Bindable:
When using @Perception.Bindable, you must wrap your view body in WithPerceptionTracking to properly observe state changes.

Scoping Stores

Use the scope method to transform a store for child views:
Source: Store.swift:26-85

Bindings

Two-Way Bindings

TCA provides special support for SwiftUI bindings through the BindableAction protocol:
In your view:
Source: Binding.swift:84-101

Custom Bindings

Create custom bindings that send specific actions:
Source: Binding+Observation.swift:271-279

Sheet Presentation

Use binding scopes for sheet presentation:
Source: Store+Observation.swift:127-159

Alerts

Present alerts using store bindings:
Source: Alert+Observation.swift:4-35

Confirmation Dialogs

Similar to alerts, confirmation dialogs use store bindings:
Source: Alert+Observation.swift:38-72

Observable State

Mark your state with @ObservableState to enable observation:
This allows SwiftUI views to automatically observe changes:
Source: Store+Observation.swift:11-25

Best Practices

Scope Early, Scope Often

Scope stores to the minimum state needed by each view:

Use WithPerceptionTracking for iOS 13-16

When supporting pre-iOS 17, always wrap view bodies in WithPerceptionTracking:
Don’t forget to also wrap lazy closures like ForEach:
Source: ObservationBackport.md:85-116

Prefer Direct Store Access

With observable state, access store properties directly: