Swift
iOS Development
Mobile App Development
Keyboard Dismissal
User Interface

Close iOS Keyboard by touching anywhere using Swift

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

A common iOS usability improvement is dismissing the keyboard when the user taps outside a text field. UIKit does not do this automatically for every screen, so you usually add a tap gesture recognizer or use one of the built-in keyboard dismissal behaviors provided by scroll views. The right solution depends on the screen, but the core idea is always the same: end editing on the current view hierarchy.

The Simple View-Controller Solution

The most common approach is to attach a tap gesture recognizer to the main view and call view.endEditing(true).

swift
1import UIKit
2
3final class LoginViewController: UIViewController {
4    override func viewDidLoad() {
5        super.viewDidLoad()
6
7        let tap = UITapGestureRecognizer(target: self, action: #selector(dismissKeyboard))
8        tap.cancelsTouchesInView = false
9        view.addGestureRecognizer(tap)
10    }
11
12    @objc private func dismissKeyboard() {
13        view.endEditing(true)
14    }
15}

view.endEditing(true) asks the current first responder, such as a UITextField or UITextView, to resign. Once that happens, the keyboard disappears.

Why cancelsTouchesInView = false Matters

This detail is easy to miss. By default, a tap gesture recognizer can prevent the touched view from receiving its normal tap handling.

If you set:

swift
tap.cancelsTouchesInView = false

then buttons and other controls still receive their touch events after the keyboard is dismissed. Without that line, you may create a subtle bug where tapping a button dismisses the keyboard but does not trigger the button action.

That is why most production implementations include it.

Make It Reusable with a Small Extension

If several screens need the same behavior, an extension keeps the setup concise:

swift
1import UIKit
2
3extension UIViewController {
4    func installKeyboardDismissRecognizer() {
5        let tap = UITapGestureRecognizer(target: self, action: #selector(endEditingFromTap))
6        tap.cancelsTouchesInView = false
7        view.addGestureRecognizer(tap)
8    }
9
10    @objc private func endEditingFromTap() {
11        view.endEditing(true)
12    }
13}

Then in each controller:

swift
1override func viewDidLoad() {
2    super.viewDidLoad()
3    installKeyboardDismissRecognizer()
4}

This works well when most of the app uses the same keyboard-dismiss-on-background-tap behavior.

Scroll Views Have a Built-In Option Too

If your form is inside a UIScrollView, UITableView, or UICollectionView, another option is keyboardDismissMode.

swift
1override func viewDidLoad() {
2    super.viewDidLoad()
3    scrollView.keyboardDismissMode = .onDrag
4}

Useful modes include:

  • '.none'
  • '.onDrag'
  • '.interactive'

This does not dismiss the keyboard on any tap, but it often creates a more natural experience for form-heavy screens where users scroll after editing.

Ignore Specific Touches When Necessary

Sometimes you do not want every tap to dismiss the keyboard. For example, you may want taps on certain controls to behave normally without the gesture recognizer interfering.

In that case, use a gesture recognizer delegate:

swift
1import UIKit
2
3final class ProfileViewController: UIViewController, UIGestureRecognizerDelegate {
4    override func viewDidLoad() {
5        super.viewDidLoad()
6
7        let tap = UITapGestureRecognizer(target: self, action: #selector(dismissKeyboard))
8        tap.cancelsTouchesInView = false
9        tap.delegate = self
10        view.addGestureRecognizer(tap)
11    }
12
13    @objc private func dismissKeyboard() {
14        view.endEditing(true)
15    }
16
17    func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
18        return !(touch.view is UIButton)
19    }
20}

This gives you fine control when a global tap recognizer would be too blunt.

Prefer endEditing Over Tracking Individual Fields

A common beginner pattern is manually calling resignFirstResponder() on each field one by one. That quickly becomes repetitive.

view.endEditing(true) is usually better because it works regardless of which field is currently active. It also keeps the code resilient as the screen evolves and more editable controls are added.

Choose the Behavior That Matches the Screen

Not every screen should dismiss the keyboard the same way.

  • login and settings screens often work well with tap-to-dismiss
  • large forms inside scroll views often feel better with drag-to-dismiss
  • highly interactive screens may need selective gesture filtering

The goal is not to add keyboard dismissal everywhere by reflex. The goal is to make the screen feel natural.

Common Pitfalls

One common mistake is forgetting cancelsTouchesInView = false, which can cause taps on buttons or table cells to stop working as expected.

Another mistake is adding multiple identical gesture recognizers over time, especially when setup code runs more than once. That can produce redundant behavior and make debugging confusing.

Developers also sometimes call resignFirstResponder() on one specific field even though another field is active. view.endEditing(true) is more robust.

Finally, on scroll-based forms, a tap recognizer may not be the best UX. Sometimes keyboardDismissMode is the cleaner built-in option.

Summary

  • The usual Swift solution is a tap gesture recognizer that calls view.endEditing(true).
  • Set cancelsTouchesInView = false so normal control taps still work.
  • For repeated use, wrap the setup in a reusable view-controller extension.
  • On scroll views, consider keyboardDismissMode as an alternative.
  • Choose the dismissal behavior that best matches the screen's interaction style.

Course illustration
Course illustration

All Rights Reserved.