How do I dismiss the keyboard when using TextEditor or TextField?

When using SwiftUI TextEditor or TextField, is there a built-in method of dismissing the keyboard? For example, if I am writing notes in a TextEditor, could I tap a "Done" button that triggers an action to dismiss the keyboard so I can view my notes full screen?

The closest solution I could find involves UIKit, but I would like to know if there is any pure SwiftUI implementation I could use.
No, unfortunately there is no method now in SwiftUI for dismissing the Keyboard you will have to use some UIkit methods
You can find a quick wrapper for the UIKit TextField.
Code Block
swift
struct CustomTextField: UIViewRepresentable {
    class Coordinator: NSObject, UITextFieldDelegate {
        @Binding var text: String
        var onCommit: (_ value: String) -> Void
        var didBecomeFirstResponder = false
        init(text: Binding<String>, onCommit: @escaping (_ value: String) -> Void) {
            _text = text
            self.onCommit = onCommit
        }
        
        func textFieldDidChangeSelection(_ textField: UITextField) {
            text = textField.text ?? ""
        }
        
        func textFieldShouldReturn(_ textField: UITextField) -> Bool {
            textField.resignFirstResponder()
            onCommit(textField.text ?? "")
            return true
        }
    }
    @Binding var text: String
    var onCommit: (_ value: String) -> Void
    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, onCommit: onCommit)
    }
    func updateUIView(_ uiView: UITextField, context: UIViewRepresentableContext<CustomTextField>) {
        uiView.text = text
        if isFirstResponder && !context.coordinator.didBecomeFirstResponder  {
            uiView.becomeFirstResponder()
            context.coordinator.didBecomeFirstResponder = true
        }
    }
}


You can further customise it with what you need.
This does indeed appear to be a sad oversight from Apple...

However thankfully there are workarounds...

Code Block swift
import Introspect
extension UITextField {
  func addDoneButton() {
    self.keyboardAppearance = .light
    let keyboardToolbar = UIToolbar()
    keyboardToolbar.sizeToFit()
     
    let flexibleSpace = UIBarButtonItem(barButtonSystemItem: .flexibleSpace,
                      target: nil, action: nil)
    let doneButton = UIBarButtonItem(barButtonSystemItem: .done,
                     target: self, action: #selector(resignFirstResponder))
    keyboardToolbar.items = [flexibleSpace, doneButton]
    self.inputAccessoryView = keyboardToolbar
  }
}
extension View {
  func addDoneButton() -> some View {
    let helper = MainViewHelper()
     
    let customise: (UITextView) -> () = { uiTextView in
      let toolBar = UIToolbar(frame: CGRect(x: 0.0,
                         y: 0.0,
                         width: UIScreen.main.bounds.size.width,
                         height: 44.0))//1
      let flexible = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
      let barButton = UIBarButtonItem(title: "Done", style: .plain, target: uiTextView, action: #selector(helper.close))
      toolBar.setItems([flexible, barButton], animated: false)//4
      uiTextView.inputAccessoryView = toolBar
      uiTextView.keyboardAppearance = .light
    }
     
    return introspect(selector: TargetViewSelector.siblingContaining, customize: customise)
  }
}
class MainViewHelper {
  @objc func close() {
     
  }
}
extension UITextView {
  func addDoneButton(title: String) {
    let textView = self
    let toolBar = UIToolbar(frame: CGRect(x: 0.0,
                       y: 0.0,
                       width: UIScreen.main.bounds.size.width,
                       height: 44.0))
    let flexible = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
    let barButton = UIBarButtonItem(title: title, style: .plain, target: textView, action: #selector(close))
    toolBar.setItems([flexible, barButton], animated: false)//4
    self.inputAccessoryView = toolBar
    self.keyboardAppearance = .light
  }
   
  @objc func close() {
    self.resignFirstResponder()
  }
}


Hello, I recently encountered the same problem as you when developing notebook tools in the program. I've also been looking for ways to use SwiftUI to solve the problem, but it seems that I can only use UIKit for now. I found a very convenient way to deal with it, I hope it can help you:

struct xxxView: View {
    ...
    .navigationBarItems(trailing:
        Button(action: {
            UIApplication.shared.endEditing()
        }) {
            Text("Finished")
            }
        )
    ...
}

...

extension UIApplication {
    func endEditing() {
        sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
    }
}

Source of this solution: https://stackoverflow.com/questions/58349955/swiftui-dismiss-keyboard-when-tapping-segmentedcontrol

How do I dismiss the keyboard when using TextEditor or TextField?
 
 
Q