Understanding the Bindable property wrapper in SwiftUI
Learn how and when to use @Bindable in SwiftUI.
03 Mar 2025 · 4 min read
When working with Apple's Observation framework, understanding how different property wrappers manage state is essential for building apps with SwiftUI.
In this article, we'll focus on @Bindable, a property wrapper that allows child views to create bindings to properties inside an @Observable model.

Let's start with an example where two views share the same view model:
import Observation@Observableclass UserViewModel {var name: String?var age: Int?}struct ParentView: View {@State private var userViewModel = UserViewModel()var body: some View {VStack {Text(userViewModel.name ?? "")ChildView(userViewModel: $userViewModel)}}}struct ChildView: View {let userViewModel: UserViewModelvar body: some View {VStack {Text(userViewModel.name ?? "")Button(action: {userViewModel.age += 1}, label: {Text("Increment age")})}}}
Why no property wrapper is needed here
In the example above, ChildView does not use any property wrapper to reference userViewModel. Since UserViewModel is marked as @Observable, SwiftUI automatically tracks changes and updates dependent views when properties change. Thus, there's no need to use @Bindable in this scenario.
When do we need @Bindable?
While direct property access works in many cases, certain UI components, such as TextField, require bindings to modify a value. Consider the following scenario:
struct ChildView: View {let userViewModel: UserViewModelvar body: some View {VStack {// Compiler error: Cannot find '$userViewModel' in scopeTextField("Enter name", text: $userViewModel.name ?? "")}}}
When we try to pass in a property of our model to a child view which needs a binding, we'll get the compiler error "Cannot find '$userViewModel' in scope".
And that's where the @Bindable property wrapper comes into play. @Bindable allows us to create bindings to properties that are part of a model:
struct ChildView: View {@Bindable var userViewModel: UserViewModelvar body: some View {VStack {TextField("Enter name", text: $userViewModel.name ?? "")}}}
Now, TextField can modify userViewModel.name, and SwiftUI will properly update the view hierarchy.



Newsletter
Like to support my work?
Say hi
Related tags
Articles with related topics
Latest articles and tips



