Fix: Keyboard Does Not Dismiss on Return in UITextField

Fix: Keyboard Does Not Dismiss on Return in UITextField

Written by

in

Quick answer: To dismiss the keyboard when pressing Return, conform your view controller to UITextFieldDelegate, set textField.delegate = self, and implement textFieldShouldReturn(_:). Inside that method, call textField.resignFirstResponder() (or view.endEditing(true)) and return true.

Why this happens

By default, tapping the Return key on an iOS software keyboard does nothing to change input focus. While UITextField generates user interaction events, UIKit leaves the decision of what “Return” means entirely to the application.

When a user taps inside a text field, that field becomes the window’s first responder (isFirstResponder == true), which prompts the operating system to display the software keyboard. Tapping the Return key invokes the delegate method textFieldShouldReturn(_:) if a delegate is attached.

Returning true from textFieldShouldReturn(_:) merely signals to the system that the default behavior for the Return key is permitted; it does not automatically resign the first responder status. If your view controller either fails to adopt UITextFieldDelegate, forgets to assign textField.delegate = self, or omits calling resignFirstResponder(), the keyboard remains locked on screen.

How to fix it

1. Assign the delegate and resign the first responder

The standard UIKit pattern requires conforming your view controller to UITextFieldDelegate, setting the text field’s delegate in code or Interface Builder, and calling resignFirstResponder() within textFieldShouldReturn(_:).

import UIKit

final class FormViewController: UIViewController, UITextFieldDelegate {

    @IBOutlet private weak var emailTextField: UITextField!

    override func viewDidLoad() {
        super.viewDidLoad()

        // Connect the delegate
        emailTextField.delegate = self
        emailTextField.returnKeyType = .done
    }

    // MARK: - UITextFieldDelegate

    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        // Dismiss the keyboard
        textField.resignFirstResponder()
        return true
    }
}

Setting returnKeyType = .done (or configuring the Return Key attribute in your storyboard) updates the keyboard label from the default “return” to “Done”, making the dismiss behavior obvious to users.

2. Dismiss via view.endEditing for containers or multiple inputs

If your screen contains multiple text inputs, labels, or buttons embedded inside a complex hierarchy, you do not need to track which specific control is currently focused. Calling endEditing(true) on the view controller’s root view searches the entire view hierarchy for the active first responder and forces it to resign.

func textFieldShouldReturn(_ textField: UITextField) -> Bool {
    view.endEditing(true)
    return true
}

This approach also works cleanly when wrapping inputs in custom container views or table view cells where direct access to the active UITextField instance might require delegate forwarding.

3. Advance to the next text field on Return

In multi-field forms (such as sign-up or checkout screens), pressing Return on the first input should focus the next field rather than dismissing the keyboard. You can chain text fields using becomeFirstResponder() and only dismiss the keyboard on the final input.

import UIKit

final class LoginViewController: UIViewController, UITextFieldDelegate {

    @IBOutlet private weak var usernameField: UITextField!
    @IBOutlet private weak var passwordField: UITextField!

    override func viewDidLoad() {
        super.viewDidLoad()

        usernameField.delegate = self
        passwordField.delegate = self

        usernameField.returnKeyType = .next
        passwordField.returnKeyType = .done
    }

    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        if textField === usernameField {
            // Move focus to password input without hiding the keyboard
            passwordField.becomeFirstResponder()
        } else if textField === passwordField {
            // Last field: dismiss keyboard
            textField.resignFirstResponder()
            submitForm()
        }
        return true
    }

    private func submitForm() {
        // Trigger authentication
    }
}

4. Handling Return dismissal in SwiftUI

If you are writing or migrating an interface to SwiftUI, text field dismissal does not rely on UITextFieldDelegate. Instead, use the @FocusState property wrapper paired with the .onSubmit view modifier.

import SwiftUI

struct ProfileEditView: View {
    @State private var nickname = ""
    @FocusState private var isFieldFocused: Bool

    var body: some View {
        Form {
            TextField("Nickname", text: $nickname)
                .focused($isFieldFocused)
                .submitLabel(.done)
                .onSubmit {
                    isFieldFocused = false
                }
        }
    }
}

Setting isFieldFocused = false inside .onSubmit resigns the underlying text field’s first responder status and closes the keyboard.

How to prevent it

  • Always connect delegate = self in viewDidLoad() or link the delegate outlet in the storyboard when adding new UITextField controls.
  • Set explicit returnKeyType values (.done, .search, .go, or .next) so the keyboard button matches the action your delegate performs.
  • Ensure isUserInteractionEnabled is set to true on any parent container views to prevent blocked touch events.
  • If using custom subclasses of UITextField, verify that canResignFirstResponder has not been overridden to return false.

FAQ

What is the difference between resignFirstResponder() and view.endEditing(true)?

resignFirstResponder() directly instructs a specific control to release input focus, while view.endEditing(true) traverses the entire subview tree to find and resign whatever element is currently active. Use resignFirstResponder() when handling a known field, and view.endEditing(true) when you want to dismiss the keyboard unconditionally.

Why is textFieldShouldReturn never being called in my view controller?

The most common cause is forgetting to assign the text field’s delegate property to your view controller. Verify that textField.delegate = self executes in viewDidLoad(), or verify that the delegate outlet is hooked up in Interface Builder.

Should textFieldShouldReturn return true or false?

In most scenarios, returning true is appropriate because it confirms that the text field should implement its standard return behavior. Returning false prevents UIKit from running any default return handling, which is occasionally useful if you wish to block submission until specific validation rules pass.

Sources & credits

Parts of this guide are adapted from content licensed under CC BY-SA 4.0; this article is shared under the same license.