How to Use @Binding in SwiftUI
What you’ll build or solve
You’ll create a child SwiftUI view that can update a value without owning that state.
When this approach works best
@Binding works best when:
Learn Swift on Mimo
- A parent view owns state and a child needs to edit it, like a form field or toggle row.
- You are building reusable components that should not store their own copy of data.
- You want to keep one source of truth while still letting nested views make updates.
This is a bad idea when the value should be owned and managed inside the child view. In that case, use @State in the child instead.
Prerequisites
- Xcode with a SwiftUI project
- You already have state owned by another view (commonly with
@State)
Example parent state (for this guide):
Swift
import SwiftUI
struct ParentView: View {
@State private var count = 0
var body: some View {
ChildView(count: $count)
}
}
Step-by-step instructions
Step 1: Declare a binding in the child view
Declare the value in the child using @Binding. The child does not own the data, it references it.
Swift
import SwiftUI
struct ChildView: View {
@Binding var count: Int
var body: some View {
Button("Increase") {
count += 1
}
}
}
What to look for
@Bindingusesvar, notlet.- Updating
counthere updates the parent’s stored value.
Step 2: Pass a binding from the parent
Pass the binding when you create the child view.
Swift
ChildView(count: $count)
What to look for
- Use
$countto pass a binding, notcount. - The binding type must match.
Binding<Int>maps to@Binding var count: Int.
Examples you can copy
Example 1: Toggle row controlled by a parent
Swift
import SwiftUI
struct SettingsView: View {
@State private var notificationsOn = false
var body: some View {
NotificationToggle(isOn: $notificationsOn)
.padding()
}
}
struct NotificationToggle: View {
@Binding var isOn: Bool
var body: some View {
Toggle("Notifications", isOn: $isOn)
}
}
Example 2: Text field component
Swift
import SwiftUI
struct ProfileForm: View {
@State private var username = ""
var body: some View {
UsernameField(username: $username)
.padding()
}
}
struct UsernameField: View {
@Binding var username: String
var body: some View {
TextField("Username", text: $username)
.textFieldStyle(.roundedBorder)
}
}
Example 3: Counter control
Swift
import SwiftUI
struct Dashboard: View {
@State private var score = 0
var body: some View {
ScoreControl(score: $score)
.padding()
}
}
struct ScoreControl: View {
@Binding var score: Int
var body: some View {
HStack(spacing: 12) {
Button("−") { score -= 1 }
Text("\(score)")
Button("+") { score += 1 }
}
}
}
Common mistakes and how to fix them
Mistake 1: Passing a value instead of a binding
What you might do:
Swift
ChildView(count: count)
Why it breaks: The child expects a binding, but you passed an Int.
Correct approach:
Swift
ChildView(count: $count)
Mistake 2: Using @State in both parent and child
What you might do:
Swift
struct ChildView: View {
@State var count: Int
}
Why it breaks: The child stores its own copy, so updates do not change the parent’s value.
Correct approach:
Swift
struct ChildView: View {
@Binding var count: Int
}
Troubleshooting
- If you see
Cannot convert value of type 'Int' to expected argument type 'Binding<Int>', pass$countinstead ofcount. - If the preview fails because a binding is missing, use a constant binding:
Swift
#Preview {
ChildView(count: .constant(0))
}
- If updates do not show up, confirm you are not accidentally creating a second source of truth with
@Statein the child. - If types do not match, align them, for example
@State var name: Stringpairs with@Binding var name: String.
Quick recap
- Declare
@Binding var value: Typein the child. - Pass the binding from the parent using
$value. - Keep one source of truth by storing data in the parent and editing it in the child.
- Match types exactly between
@Stateand@Binding. - Use
.constant(...)bindings for previews.
Join 35M+ people learning for free on Mimo
4.8 out of 5 across 1M+ reviews
Check us out on Apple AppStore, Google Play Store, and Trustpilot