Logo for tanaschita.com

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.

Sponsorship logo
Architecture & Design Patterns for iOS
This book is a practical guide to essential architectural principles and design patterns for iOS development. It covers strategies for building maintainable apps with Swift and SwiftUI, including dependency injection, navigation, common patterns, and modularization.
LEARN MORE

Let's start with an example where two views share the same view model:

import Observation
@Observable
class 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: UserViewModel
var 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: UserViewModel
var body: some View {
VStack {
// Compiler error: Cannot find '$userViewModel' in scope
TextField("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: UserViewModel
var body: some View {
VStack {
TextField("Enter name", text: $userViewModel.name ?? "")
}
}
}

Now, TextField can modify userViewModel.name, and SwiftUI will properly update the view hierarchy.

Sponsorship logo
Preparing for a technical iOS job interview
Preparing for a technical iOS Job Interview with over 300 questions & answers. Covering Swift & Objective-C, SwiftUI & UIKit, Combine, HTTP Networking, iOS File System, Core Data, Concurrency with async/await, Security, Automated Testing, Dependency Management, AI & Machine Learning and more.
LEARN MORE
Sponsorship logo
Architecture & Design Patterns for iOS
This book is a practical guide to essential architectural principles and design patterns for iOS development. It covers strategies for building maintainable apps with Swift and SwiftUI, including dependency injection, navigation, common patterns, and modularization.
LEARN MORE
Sponsorship logo
Become a sponsor of tanaschita.com
By publishing an article on different iOS topics every week, tanaschita.com is constantly growing in the developer community and may provide a great audience for you as a sponsor.
CLICK TO LEARN MORE

Newsletter

Image of a reading marmot
Subscribe

Like to support my work?

Say hi

Related tags

Articles with related topics

swiftui

property wrappers

swift

ios

Presenting alerts and confirmation dialogs from identifiable data in SwiftUI

Learn how to present alerts and confirmation dialogs using optional identifiable items instead of Boolean state.

24 Aug 2026 · 4 min read

Latest articles and tips

© 2026 tanaschita.com

Privacy policy

Impressum