SwiftUI: How to make TextField become first responder?

SwiftTextfieldSwiftuiFirst Responder

Swift Problem Overview


Here's my SwiftUI code:

struct ContentView : View {

    @State var showingTextField = false
    @State var text = ""

    var body: some View {
        return VStack {
            if showingTextField {
                TextField($text)
            }
            Button(action: { self.showingTextField.toggle() }) {
                Text ("Show")
            }
        }
    }
}

What I want is when the text field becomes visible, to make the text field become the first responder (i.e. receive focus & have the keyboard pop up).

Swift Solutions


Solution 1 - Swift

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

Solution 2 - Swift

Using SwiftUI-Introspect, you can do:

TextField("", text: $value)
.introspectTextField { textField in
    textField.becomeFirstResponder()
}

Solution 3 - Swift

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

Solution 4 - Swift

For anyone who ended up here but faced crashed using @Matteo Pacini's answer, please be aware of this change in beta 4: https://stackoverflow.com/questions/57178382/cannot-assign-to-property-text-is-immutable/57179008#57179008 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 ?? ""
        }
    }
}

Solution 5 - Swift

iOS 15.0+

macOS 12.0+,

Mac Catalyst 15.0+,

tvOS 15.0+,

watchOS 8.0+

Use focused(_:) if you have a single TextField.

> focused(_:) > > Modifies this view by binding its focus state to the given Boolean state value.

struct NameForm: View {
    
    @FocusState private var isFocused: Bool
    
    @State private var name = ""
    
    var body: some View {
        TextField("Name", text: $name)
            .focused($isFocused)
        
        Button("Submit") {
            if name.isEmpty {
                isFocued = true
            }
        }
    }
}

Use focused(_:equals:) should you have multiple TextFields.

> focused(_:equals:) > > Modifies this view by binding its focus state to the given state value.

struct LoginForm: View {
    enum Field: Hashable {
        case usernameField
        case passwordField
    }

    @State private var username = ""
    @State private var password = ""
    @FocusState private var focusedField: Field?

    var body: some View {
        Form {
            TextField("Username", text: $username)
                .focused($focusedField, equals: .usernameField)

            SecureField("Password", text: $password)
                .focused($focusedField, equals: .passwordField)

            Button("Sign In") {
                if username.isEmpty {
                    focusedField = .usernameField
                } else if password.isEmpty {
                    focusedField = .passwordField
                } else {
                    handleLogin(username, password)
                }
            }
        }
    }
}
SwiftUI Documentation

Update

I tested this in xCode version 13.0 beta 5 (13A5212g). It works

Solution 6 - Swift

 ResponderChain

I made this small package for cross-platform first responder handling without subclassing views or making custom ViewRepresentables in SwiftUI on iOS 13+

https://github.com/Amzd/ResponderChain

How to apply it to your problem

SceneDelegate.swift

...
// Set the ResponderChain as environmentObject
let rootView = ContentView().environmentObject(ResponderChain(forWindow: window))
...

ContentView.swift

struct ContentView: View {

    @EnvironmentObject var chain: ResponderChain
    @State var showingTextField = false
    @State var text = ""

    var body: some View {
        return VStack {
            if showingTextField {
                TextField($text).responderTag("field1").onAppear {
                    DispatchQueue.main.async {
                        chain.firstResponder = "field1"
                    }
                }
            }
            Button(action: { self.showingTextField.toggle() }) {
                Text ("Show")
            }
        }
    }
}

Solution 7 - Swift

As others have noted (e.g. @kipelovets comment on the accepted answer, e.g. @Eonil's answer), I have also not found any of the accepted solutions to work on macOS. I've had some luck, however, using NSViewControllerRepresentable to get a NSSearchField to appear as the first responder in a SwiftUI view:

import Cocoa
import SwiftUI

class FirstResponderNSSearchFieldController: NSViewController {

  @Binding var text: String

  init(text: Binding<String>) {
    self._text = text
    super.init(nibName: nil, bundle: nil)
  }

  required init?(coder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
  }

  override func loadView() {
    let searchField = NSSearchField()
    searchField.delegate = self
    self.view = searchField
  }

  override func viewDidAppear() {
    self.view.window?.makeFirstResponder(self.view)
  }
}

extension FirstResponderNSSearchFieldController: NSSearchFieldDelegate {

  func controlTextDidChange(_ obj: Notification) {
    if let textField = obj.object as? NSTextField {
      self.text = textField.stringValue
    }
  }
}

struct FirstResponderNSSearchFieldRepresentable: NSViewControllerRepresentable {

  @Binding var text: String

  func makeNSViewController(
    context: NSViewControllerRepresentableContext<FirstResponderNSSearchFieldRepresentable>
  ) -> FirstResponderNSSearchFieldController {
    return FirstResponderNSSearchFieldController(text: $text)
  }

  func updateNSViewController(
    _ nsViewController: FirstResponderNSSearchFieldController,
    context: NSViewControllerRepresentableContext<FirstResponderNSSearchFieldRepresentable>
  ) {
  }
}

Sample SwiftUI view:

struct ContentView: View {

  @State private var text: String = ""

  var body: some View {
    FirstResponderNSSearchFieldRepresentable(text: $text)
  }
}

Solution 8 - Swift

To fill in this missing functionality, you may install SwiftUIX using Swift Package Manager:

  1. In Xcode, open your project and navigate to File → Swift Packages → Add Package Dependency...
  2. Paste the repository URL (https://github.com/SwiftUIX/SwiftUIX) and click Next.
  3. For Rules, select Branch (with branch set to master).
  4. Click Finish.
  5. Open the Project settings, add SwiftUI.framework to the Linked Frameworks and Libraries, set Status to Optional.

More Info: https://github.com/SwiftUIX/SwiftUIX

import SwiftUI
import SwiftUIX

struct ContentView : View {

    @State var showingTextField = false
    @State var text = ""

    var body: some View {
        return VStack {
            if showingTextField {
                CocoaTextField("Placeholder text", text: $text)
                    .isFirstResponder(true)
                    .frame(width: 300, height: 48, alignment: .center)
            }
            Button(action: { self.showingTextField.toggle() }) {
                Text ("Show")
            }
        }
    }
}

Solution 9 - Swift

In my case I wanted to focused a textfield just right away I used .onappear function

struct MyView: View {
    
    @FocusState private var isTitleTextFieldFocused: Bool

    @State private var title = ""
    
    var body: some View {
        VStack {
            TextField("Title", text: $title)
                .focused($isTitleTextFieldFocused)
            
        }
        .padding()
        .onAppear {
            DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
                self.isTitleTextFieldFocused = true
            }
            
        }
    }
}

Solution 10 - Swift

We have a solution that makes controlling the first responder effortless.

https://github.com/mobilinked/MbSwiftUIFirstResponder

TextField("Name", text: $name)
    .firstResponder(id: FirstResponders.name, firstResponder: $firstResponder, resignableUserOperations: .all)

TextEditor(text: $notes)
    .firstResponder(id: FirstResponders.notes, firstResponder: $firstResponder, resignableUserOperations: .all)

Solution 11 - Swift

Not really an answer, just building on Casper's great solution with a convenient modifier -

struct StartInput: ViewModifier {
    
    @EnvironmentObject var chain: ResponderChain
    
    private let tag: String
    
    
    init(tag: String) {
        self.tag = tag
    }
    
    func body(content: Content) -> some View {
        
        content.responderTag(tag).onAppear() {
            DispatchQueue.main.async {
                chain.firstResponder = tag
            }
        }
    }
}


extension TextField {
    
    func startInput(_ tag: String = "field") -> ModifiedContent<TextField<Label>, StartInput> {
        self.modifier(StartInput(tag: tag))
    }
}

Just use like -

TextField("Enter value:", text: $quantity)
    .startInput()

Solution 12 - Swift

This is a ViewModifier that works with introspect. It works for AppKit MacOS, Xcode 11.5

    struct SetFirstResponderTextField: ViewModifier {
      @State var isFirstResponderSet = false
   
      func body(content: Content) -> some View {
         content
            .introspectTextField { textField in
            if self.isFirstResponderSet == false {
               textField.becomeFirstResponder()
               self.isFirstResponderSet = true
            }
         }
      }
   }

Solution 13 - Swift

SwiftUI

struct ContentView: View {
enum Field {
    case firstTextfield
    case secondTextfield
    case lastTextfield
}

@State private var firstTextfield = ""
@State private var secondTextfield = ""
@State private var lastTextfield = ""
@FocusState private var focusedField: Field?

var body: some View {
    VStack {
        TextField("Enter anything on first textfield", text: $firstTextfield)
            .focused($focusedField, equals: .firstTextfield)
            .submitLabel(.next)

        TextField("Enter anything on second textfield", text: $secondTextfield)
            .focused($focusedField, equals: .secondTextfield)
            .submitLabel(.next)

        TextField("Enter anything on last textfield", text: $lastTextfield)
            .focused($focusedField, equals: .lastTextfield)
            .submitLabel(.join)
    }
    .onSubmit {
        switch focusedField {
        case .firstTextfield:
            focusedField = .secondTextfield
        case .secondTextfield:
            focusedField = .lastTextfield
        default:
            focusedField = nil
        }
    }
  }
}

Description: Add an enum with textfields cases, and a property wrapped in a @FocusState with type of that enum. Add focused(_:equals:) modifier to have a binding value, equal to the enum cases. Now, you can change the focusedField to whichever textfield you want to have cursor on, or resign first responder by assigning nil to focusedField.

Solution 14 - Swift

Selected answer causes some infinite loop issue with AppKit. I don't know about UIKit case.

To avoid that issue, I recommend just sharing NSTextField instance directly.

import AppKit
import SwiftUI

struct Sample1: NSViewRepresentable {
    var textField: NSTextField
    func makeNSView(context:NSViewRepresentableContext<Sample1>) -> NSView { textField }
    func updateNSView(_ x:NSView, context:NSViewRepresentableContext<Sample1>) {}
}

You can use that like this.

let win = NSWindow()
let txt = NSTextField()
win.setIsVisible(true)
win.setContentSize(NSSize(width: 256, height: 256))
win.center()
win.contentView = NSHostingView(rootView: Sample1(textField: txt))
win.makeFirstResponder(txt)

let app = NSApplication.shared
app.setActivationPolicy(.regular)
app.run()

This breaks pure value semantic, but depending on AppKit means you partially abandon pure value semantic and gonna afford some dirtiness. This is a magic hole we need right now for deal with lack of first-responder control in SwiftUI.

As we access NSTextField directly, setting first-responder is plain AppKit way, therefore no visible source of trouble.

You can download working source code here.

Solution 15 - Swift

Since Responder Chain is not available to be consumed via SwiftUI, so we have to consume it using UIViewRepresentable.

Do have a look at the below link as I have made a workaround that can work similarly to the way we use to do using UIKit.

https://stackoverflow.com/a/61121199/6445871

Solution 16 - Swift

It is my variant of the implementation, based on @Mojtaba Hosseini and @Matteo Pacini solutions. I am still new to SwiftUI, so I won't guarantee the absolute correctness of the code, but it works.

I hope it would be helpful to someone.

ResponderView: It is a generic-responder view, that could be used with any UIKit view.

struct ResponderView<View: UIView>: UIViewRepresentable {
    @Binding var isFirstResponder: Bool
    var configuration = { (view: View) in }
    
    func makeUIView(context: UIViewRepresentableContext<Self>) -> View { View() }
    
    func makeCoordinator() -> Coordinator {
        Coordinator($isFirstResponder)
    }
    
    func updateUIView(_ uiView: View, context: UIViewRepresentableContext<Self>) {
        context.coordinator.view = uiView
        _ = isFirstResponder ? uiView.becomeFirstResponder() : uiView.resignFirstResponder()
        configuration(uiView)
    }
}

// MARK: - Coordinator
extension ResponderView {
    final class Coordinator {
        @Binding private var isFirstResponder: Bool
        private var anyCancellable: AnyCancellable?
        fileprivate weak var view: UIView?
        
        init(_ isFirstResponder: Binding<Bool>) {
            _isFirstResponder = isFirstResponder
            self.anyCancellable = Publishers.keyboardHeight.sink(receiveValue: { [weak self] keyboardHeight in
                guard let view = self?.view else { return }
                DispatchQueue.main.async { self?.isFirstResponder = view.isFirstResponder }
            })
        }
    }
}

// MARK: - keyboardHeight
extension Publishers {
    static var keyboardHeight: AnyPublisher<CGFloat, Never> {
        let willShow = NotificationCenter.default.publisher(for: UIApplication.keyboardWillShowNotification)
            .map { ($0.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect)?.height ?? 0 }
        
        let willHide = NotificationCenter.default.publisher(for: UIApplication.keyboardWillHideNotification)
            .map { _ in CGFloat(0) }
        
        return MergeMany(willShow, willHide)
            .eraseToAnyPublisher()
    }
}

struct ResponderView_Previews: PreviewProvider {
    static var previews: some View {
        ResponderView<UITextField>.init(isFirstResponder: .constant(false)) {
            $0.placeholder = "Placeholder"
        }.previewLayout(.fixed(width: 300, height: 40))
    }
}

ResponderTextField - It is a convenient text-field wrapper around ResponderView.

struct ResponderTextField: View {
    var placeholder: String
    @Binding var text: String
    @Binding var isFirstResponder: Bool
    private var textFieldDelegate: TextFieldDelegate
    
    init(_ placeholder: String, text: Binding<String>, isFirstResponder: Binding<Bool>) {
        self.placeholder = placeholder
        self._text = text
        self._isFirstResponder = isFirstResponder
        self.textFieldDelegate = .init(text: text)
    }
    
    var body: some View {
        ResponderView<UITextField>(isFirstResponder: $isFirstResponder) {
            $0.text = self.text
            $0.placeholder = self.placeholder
            $0.delegate = self.textFieldDelegate
        }
    }
}

// MARK: - TextFieldDelegate
private extension ResponderTextField {
    final class TextFieldDelegate: NSObject, UITextFieldDelegate {
        @Binding private(set) var text: String
        
        init(text: Binding<String>) {
            _text = text
        }
        
        func textFieldDidChangeSelection(_ textField: UITextField) {
            text = textField.text ?? ""
        }
    }
}

struct ResponderTextField_Previews: PreviewProvider {
    static var previews: some View {
        ResponderTextField("Placeholder",
                           text: .constant(""),
                           isFirstResponder: .constant(false))
            .previewLayout(.fixed(width: 300, height: 40))
    }
}

And way to use that.

struct SomeView: View {
    @State private var login: String = ""
    @State private var password: String = ""
    @State private var isLoginFocused = false
    @State private var isPasswordFocused = false
    
    var body: some View {
        VStack {
            ResponderTextField("Login", text: $login, isFirstResponder: $isLoginFocused)
            ResponderTextField("Password", text: $password, isFirstResponder: $isPasswordFocused)
        }
    }
}

Solution 17 - Swift

Expanding on @JoshuaKifer answer's above, if you're dealing with the navigation animation being glitchy when using Introspect to make a text field first responder. Use this:

import SchafKit

@State var field: UITextField?

TextField("", text: $value)
.introspectTextField { textField in
    field = textField
}
.onDidAppear {
     field?.becomeFirstResponder()
}

More details on this solution here.

Solution 18 - Swift

I took a little bit different approach - instead of UIViewRepresentable based on UITextField i made it based on UIView and and plug it in SwiftUI view hierarchy with background modifier. Inside UIView i added logic to find first view that canBecomeFirstResponder in subviews and parent views.

private struct FocusableUIView: UIViewRepresentable {
    var isFirstResponder: Bool = false

    class Coordinator: NSObject {
        var didBecomeFirstResponder = false
    }

    func makeUIView(context: UIViewRepresentableContext<FocusableUIView>) -> UIView {
        let view = UIView()
        view.backgroundColor = .clear
        return view
    }

    func makeCoordinator() -> FocusableUIView.Coordinator {
        return Coordinator()
    }

    func updateUIView(_ uiView: UIView, context: UIViewRepresentableContext<FocusableUIView>) {
        guard uiView.window != nil, isFirstResponder, !context.coordinator.didBecomeFirstResponder else {
            return
        }

        var foundRepsonder: UIView?
        var currentSuperview: UIView? = uiView
        repeat {
            foundRepsonder = currentSuperview?.subviewFirstPossibleResponder
            currentSuperview = currentSuperview?.superview
        } while foundRepsonder == nil && currentSuperview != nil

        guard let responder = foundRepsonder else {
            return
        }

        DispatchQueue.main.async {
            responder.becomeFirstResponder()
            context.coordinator.didBecomeFirstResponder = true
        }
    }
}

private extension UIView {
    var subviewFirstPossibleResponder: UIView? {
        guard !canBecomeFirstResponder else { return self }

        for subview in subviews {
            if let firstResponder = subview.subviewFirstPossibleResponder {
                return firstResponder
            }
        }

        return nil
    }
}


Here is an example how to use it to make TextField to autofocus (+ bonus utilise @FocusState new iOS 15 api).

extension View {
    @ViewBuilder
    func autofocus() -> some View {
        if #available(iOS 15, *) {
            modifier(AutofocusedViewModifiers.Modern())
        } else {
            modifier(AutofocusedViewModifiers.Legacy())
        }
    }
}

private enum AutofocusedViewModifiers {
    struct Legacy: ViewModifier {
        func body(content: Content) -> some View {
            content
                .background(FocusableUIView(isFirstResponder: isFocused))
                .onAppear {
                    DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
                        isFocused = true
                    }
                }
        }

        @State private var isFocused = false
    }

    @available(iOS 15, *)
    struct Modern: ViewModifier {
        func body(content: Content) -> some View {
            content
                .focused($isFocused)
                .onAppear {
                    DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
                        isFocused = true
                    }
                }
        }

        @FocusState private var isFocused: Bool
    }
}

Content view example:

struct ContentView: View {
    @State private var text = ""

    var body: some View {
        VStack {
            TextField("placeholder", text: $text)
            Text("some text")
        }
        .autofocus()
    }
}

Solution 19 - Swift

If you're having any problem with @JoshuaKifer or @ahaze 's response, I've solved mine by using the modifier on the parent class, instead of on the TextField itself.

What I was doing:

TextField("Placeholder text...", text: $searchInput)
    .introspectTextField { textField in
        textField.becomeFirstResponder()
    }

How I solved my problem:

   YourParentStruct(searchInput: $searchInput)
       .introspectTextField { textField in
           textField.becomeFirstResponder()
       }

I'll put the definition of the parent struct below just for clearness

   struct YourParentStruct: View {
       @Binding var searchInput: String

       var body: some View {
           HStack {
               TextField("Placeholder text...", text: $searchInput)                      
                  .padding()
                  .background(Color.gray)
                  .cornerRadius(10)
           }
       }
   }

Solution 20 - Swift

At its Simplest form in iOS 13 ( without using any third party sdk/repo , or if you havent upgraded to iOS 14 to utilise the focus modifiers)

struct CustomTextField: UIViewRepresentable {
            
    func makeUIView(context: Context) -> UITextField {
         UITextField(frame: .zero)
    }
    
    func updateUIView(_ uiView: UITextField, context: Context) {
        uiView.becomeFirstResponder()
    }
}

Usage:

struct ContentView : View {

    var body: some View {
        CustomTextField()
            .frame(width: 300, height: 50)
            .background(Color.red)
    }
}

Solution 21 - Swift

The correct SwiftUI way is to use @FocusState as mentioned above. However this API is available only for iOS 15. If you are using iOS 14 or iOS 13 you can use the Focuser library which is modelled to follow Apple API.

https://github.com/art-technologies/swift-focuser

enter image description here

Here's an example code. You will notice that API looks almost exactly as Apple, however Focuser also offers to use keyboard to move first responder down the chain which is pretty handy.

enter image description here

Solution 22 - Swift

As SwiftUI 2 doesn't support first responders yet I use this solution. It is dirty, but might work for some use cases when you only have 1 UITextField and 1 UIWindow.

import SwiftUI

struct MyView: View {
    @Binding var text: String

    var body: some View {
        TextField("Hello world", text: $text)
            .onAppear {
                UIApplication.shared.windows.first?.rootViewController?.view.textField?.becomeFirstResponder()
            }
    }
}

private extension UIView {
    var textField: UITextField? {
        subviews.compactMap { $0 as? UITextField }.first ??
            subviews.compactMap { $0.textField }.first
    }
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionEpagaView Question on Stackoverflow
Solution 1 - SwiftMatteo PaciniView Answer on Stackoverflow
Solution 2 - SwiftJoshua KiferView Answer on Stackoverflow
Solution 3 - SwiftMojtaba HosseiniView Answer on Stackoverflow
Solution 4 - SwiftRui YingView Answer on Stackoverflow
Solution 5 - SwiftmahanView Answer on Stackoverflow
Solution 6 - SwiftCasper ZandbergenView Answer on Stackoverflow
Solution 7 - SwiftDavid MullerView Answer on Stackoverflow
Solution 8 - SwiftJoanna J.View Answer on Stackoverflow
Solution 9 - SwiftDasogaView Answer on Stackoverflow
Solution 10 - Swiftswift codeView Answer on Stackoverflow
Solution 11 - SwiftSomaManView Answer on Stackoverflow
Solution 12 - SwiftGregor BrandtView Answer on Stackoverflow
Solution 13 - SwiftAashishView Answer on Stackoverflow
Solution 14 - SwifteonilView Answer on Stackoverflow
Solution 15 - SwiftAnshuman SinghView Answer on Stackoverflow
Solution 16 - SwiftDmytro ShvetsovView Answer on Stackoverflow
Solution 17 - SwiftNadia SiddiqahView Answer on Stackoverflow
Solution 18 - Swiftalex1704View Answer on Stackoverflow
Solution 19 - SwiftGabriel D MView Answer on Stackoverflow
Solution 20 - SwiftNaishtaView Answer on Stackoverflow
Solution 21 - SwiftMarkonView Answer on Stackoverflow
Solution 22 - SwiftvauxhallView Answer on Stackoverflow