DEV Community

Cover image for How to use the @FocusState property wrapper in SwiftUI
Maegan Wilson
Maegan Wilson

Posted on • Originally published at cctplus.dev

How to use the @FocusState property wrapper in SwiftUI

Here’s how to make TextFields focused and not let a form close until the proper fields are filled out by the user.


This article is also a video

WWDC 2021 introduced the property wrapper @FocusState. It can be used to set which textfields are in focus pretty easily. I’m going to open this form for adding a new bag of coffee an app I’m working on.

Notice how when I click on save it just closes the form and doesn’t dismiss the keyboard. The @FocusState can help fix that. First thing that needs to be added is an enum with the fields that we want to be required.

private enum Field { case name case style case roaster } 
Enter fullscreen mode Exit fullscreen mode

The enum needs to conform to the Hashable protocol so you can either force conformance by adding : Hashable or as long as the cases don’t have a value assigned you should be good since Swift will do that “automagically”.

Now, we need to add a variable with the property wrapper @FocusState private var focusField: Field
Then on the TextFields, add the focused modifier and what field it should be equal to

TextField("Name", text: $beans.name) .textFieldStyle(.roundedBorder) .focused($focusedField, equals: .name) TextField("Style", text: $beans.style) .textFieldStyle(.roundedBorder) .focused($focusedField, equals: .style) TextField("Roaster", text: $beans.roaster) .textFieldStyle(.roundedBorder) .focused($focusedField, equals: .roaster) 
Enter fullscreen mode Exit fullscreen mode

Next, let’s put some logic in to make sure these fields are filled and set the next focusedField

Button { if beans.name.isEmpty { focusedField = .name } else if beans.style.isEmpty { focusedField = .style } else if beans.roaster.isEmpty { focusedField = .roaster } else { if isEdit { beans.updateBean(context: viewContext) } else { beans.addBeansToData(context: viewContext) resetBeans() } showForm = false } } 
Enter fullscreen mode Exit fullscreen mode

Also, after a successful save, we should set the focusedfield to nil and dismiss the keyboard

Button { if beans.name.isEmpty { focusedField = .name } else if beans.style.isEmpty { focusedField = .style } else if beans.roaster.isEmpty { focusedField = .roaster } else { if isEdit { beans.updateBean(context: viewContext) } else { beans.addBeansToData(context: viewContext) resetBeans() } showForm = false focusedField = nil } } 
Enter fullscreen mode Exit fullscreen mode

Now, let’s run through the form one more time to just show it all together.

Hopefully that showed you how to use the @FocusState property wrapper. If you have any questions, then please drop a comment below.


Want my posts directly to your inbox?
Great! Sign up here!

Top comments (0)