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):
importSwiftUI
structParentView:View {
@Stateprivatevarcount=0
varbody:someView {
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.
importSwiftUI
structChildView:View {
@Bindingvarcount:Int
varbody:someView {
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.
PHP
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
importSwiftUI
structSettingsView:View {
@StateprivatevarnotificationsOn=false
varbody:someView {
NotificationToggle(isOn: $notificationsOn)
.padding()
}
}
structNotificationToggle:View {
@BindingvarisOn:Bool
varbody:someView {
Toggle("Notifications",isOn: $isOn)
}
}
Example 2: Text field component
importSwiftUI
structProfileForm:View {
@Stateprivatevarusername=""
varbody:someView {
UsernameField(username: $username)
.padding()
}
}
structUsernameField:View {
@Bindingvarusername:String
varbody:someView {
TextField("Username",text: $username)
.textFieldStyle(.roundedBorder)
}
}
Example 3: Counter control
importSwiftUI
structDashboard:View {
@Stateprivatevarscore=0
varbody:someView {
ScoreControl(score: $score)
.padding()
}
}
structScoreControl:View {
@Bindingvarscore:Int
varbody:someView {
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:
ChildView(count:count)
Why it breaks: The child expects a binding, but you passed an Int.
Correct approach:
PHP
ChildView(count: $count)
Mistake 2: Using @State in both parent and child
What you might do:
SQL
structChildView:View {
@Statevarcount:Int
}
Why it breaks: The child stores its own copy, so updates do not change the parent’s value.
Correct approach:
SQL
structChildView:View {
@Bindingvarcount: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:
#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