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()
}

iOS 15

There is a new wrapper called @FocusState that controls the state of the keyboard and the focused keyboard ('aka' firstResponder).

Become First Responder ( Focused )

If you use a focused modifier on the text fields, you can make them become focused:

enter image description here

Resign first responder ( Dismiss keyboard )

or dismiss the keyboard by setting the variable to nil:

enter image description here



iOS 13 and above: Old but working!

Simple wrapper struct - Works like a native:

Note that Text binding support added as requested in the comments

struct LegacyTextField: UIViewRepresentable {
    @Binding public var isFirstResponder: Bool
    @Binding public var text: String

    public var configuration = { (view: UITextField) in }

    public init(text: Binding<String>, isFirstResponder: Binding<Bool>, configuration: @escaping (UITextField) -> () = { _ in }) {
        self.configuration = configuration
        self._text = text
        self._isFirstResponder = isFirstResponder
    }

    public func makeUIView(context: Context) -> UITextField {
        let view = UITextField()
        view.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
        view.addTarget(context.coordinator, action: #selector(Coordinator.textViewDidChange), for: .editingChanged)
        view.delegate = context.coordinator
        return view
    }

    public func updateUIView(_ uiView: UITextField, context: Context) {
        uiView.text = text
        configuration(uiView)
        switch isFirstResponder {
        case true: uiView.becomeFirstResponder()
        case false: uiView.resignFirstResponder()
        }
    }

    public func makeCoordinator() -> Coordinator {
        Coordinator($text, isFirstResponder: $isFirstResponder)
    }

    public class Coordinator: NSObject, UITextFieldDelegate {
        var text: Binding<String>
        var isFirstResponder: Binding<Bool>

        init(_ text: Binding<String>, isFirstResponder: Binding<Bool>) {
            self.text = text
            self.isFirstResponder = isFirstResponder
        }

        @objc public func textViewDidChange(_ textField: UITextField) {
            self.text.wrappedValue = textField.text ?? ""
        }

        public func textFieldDidBeginEditing(_ textField: UITextField) {
            self.isFirstResponder.wrappedValue = true
        }

        public func textFieldDidEndEditing(_ textField: UITextField) {
            self.isFirstResponder.wrappedValue = false
        }
    }
}

Usage:

struct ContentView: View {
    @State var text = ""
    @State var isFirstResponder = false

    var body: some View {
        LegacyTextField(text: $text, isFirstResponder: $isFirstResponder)
    }
}

🎁 Bonus: Completely customizable

LegacyTextField(text: $text, isFirstResponder: $isFirstResponder) {
    $0.textColor = .red
    $0.tintColor = .blue
}

This method is fully adaptable. For example, you can see How to add an Activity indicator in SwiftUI with the same method here