SwiftUI: How to make TextField become first responder?
Swift UI 3
As of Xcode 13, you can use the focused
modifier to make a view become first responder.
Swift UI 1/2
It doesn't seem to be possible at the moment, but you can implement something similar yourself.
You can create a custom text field and add a value to make it become first responder.
struct CustomTextField: UIViewRepresentable { class Coordinator: NSObject, UITextFieldDelegate { @Binding var text: String var didBecomeFirstResponder = false init(text: Binding<String>) { _text = text } func textFieldDidChangeSelection(_ textField: UITextField) { text = textField.text ?? "" } } @Binding var text: String var isFirstResponder: Bool = false func makeUIView(context: UIViewRepresentableContext<CustomTextField>) -> UITextField { let textField = UITextField(frame: .zero) textField.delegate = context.coordinator return textField } func makeCoordinator() -> CustomTextField.Coordinator { return Coordinator(text: $text) } func updateUIView(_ uiView: UITextField, context: UIViewRepresentableContext<CustomTextField>) { uiView.text = text if isFirstResponder && !context.coordinator.didBecomeFirstResponder { uiView.becomeFirstResponder() context.coordinator.didBecomeFirstResponder = true } }}
Note: didBecomeFirstResponder
is needed to make sure the text field becomes first responder only once, not on every refresh by SwiftUI
!
You would use it like this...
struct ContentView : View { @State var text: String = "" var body: some View { CustomTextField(text: $text, isFirstResponder: true) .frame(width: 300, height: 50) .background(Color.red) }}
P.S. I added a frame
as it doesn't behave like the stock TextField
, meaning there's more stuff going on behind the scenes.
More on Coordinators
in this excellent WWDC 19 talk:Integrating SwiftUI
Tested on Xcode 11.4
Using SwiftUI-Introspect, you can do:
TextField("", text: $value).introspectTextField { textField in textField.becomeFirstResponder()}
For anyone who ended up here but faced crashed using @Matteo Pacini's answer, please be aware of this change in beta 4: Cannot assign to property: '$text' is immutable about this block:
init(text: Binding<String>) { $text = text}
should use:
init(text: Binding<String>) { _text = text}
And if you want to make the textfield become first responder in a sheet
, please be aware that you cannot call becomeFirstResponder
until the textfield is shown. In other words, putting @Matteo Pacini's textfield directly in sheet
content causes crash.
To solve the issue, add an additional check uiView.window != nil
for textfield's visibility. Only focus after it is in the view hierarchy:
struct AutoFocusTextField: UIViewRepresentable { @Binding var text: String func makeCoordinator() -> Coordinator { Coordinator(self) } func makeUIView(context: UIViewRepresentableContext<AutoFocusTextField>) -> UITextField { let textField = UITextField() textField.delegate = context.coordinator return textField } func updateUIView(_ uiView: UITextField, context: UIViewRepresentableContext<AutoFocusTextField>) { uiView.text = text if uiView.window != nil, !uiView.isFirstResponder { uiView.becomeFirstResponder() } } class Coordinator: NSObject, UITextFieldDelegate { var parent: AutoFocusTextField init(_ autoFocusTextField: AutoFocusTextField) { self.parent = autoFocusTextField } func textFieldDidChangeSelection(_ textField: UITextField) { parent.text = textField.text ?? "" } }}