Swift
UITextField
iOS Development
Disable Input
Swift Programming

Disabling user input for UITextfield in swift

Master System Design with Codemia

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

Introduction

UITextField is one of the most commonly used input controls in iOS, but there are many situations where you need to prevent the user from typing freely. You might want a read-only display field, a field that only accepts input from a picker, or a field that conditionally locks based on app state. Swift gives you several ways to accomplish this, each with different visual and behavioral trade-offs. This article covers four approaches so you can pick the one that fits your use case.

Using isUserInteractionEnabled

The most straightforward way to block all interaction with a text field is to set isUserInteractionEnabled to false. This disables taps, long presses, and keyboard input entirely.

swift
let readOnlyField = UITextField()
readOnlyField.text = "This value cannot be changed"
readOnlyField.isUserInteractionEnabled = false

When you use this property, the text field does not change its visual appearance. It still looks like a normal, active field. This can confuse users because they see a text field but nothing happens when they tap it. If you go this route, consider changing the text color or background to hint that the field is not interactive:

swift
readOnlyField.textColor = .gray
readOnlyField.backgroundColor = UIColor.systemGray6

One key detail: because all interaction is disabled, the user cannot even select or copy the text. If you need selectable-but-not-editable text, this approach will not work.

Using isEnabled

The isEnabled property is inherited from UIControl and is designed specifically for toggling a control between active and inactive states. Setting it to false dims the text field automatically, giving the user a clear visual signal.

swift
let lockedField = UITextField()
lockedField.text = "Account verified"
lockedField.isEnabled = false

The difference from isUserInteractionEnabled is that UIKit applies a default dimmed appearance when isEnabled is false. The field also stops sending control events. This is the right choice when you want the standard "disabled control" look that users already recognize from buttons and switches:

swift
1// Toggle based on a condition
2func updateFieldState(isEditable: Bool) {
3    nameField.isEnabled = isEditable
4    emailField.isEnabled = isEditable
5}

Like isUserInteractionEnabled, this prevents text selection and copying. The text field will not become the first responder, so the keyboard never appears.

Using the UITextFieldDelegate

If you need finer-grained control, such as allowing the user to tap the field and see the cursor but blocking actual character entry, you can use the UITextFieldDelegate protocol. The textField(_:shouldChangeCharactersIn:replacementString:) method is called every time the user tries to insert or delete text. Returning false silently rejects the change.

swift
1class FormViewController: UIViewController, UITextFieldDelegate {
2
3    @IBOutlet weak var statusField: UITextField!
4
5    override func viewDidLoad() {
6        super.viewDidLoad()
7        statusField.delegate = self
8    }
9
10    func textField(
11        _ textField: UITextField,
12        shouldChangeCharactersIn range: NSRange,
13        replacementString string: String
14    ) -> Bool {
15        if textField == statusField {
16            return false  // Block all edits for this field
17        }
18        return true  // Allow edits for other fields
19    }
20}

This approach is powerful because the field still becomes the first responder. The keyboard appears, the cursor blinks, and the user can select and copy text. You are only blocking mutation. This is useful when you want to show the keyboard for other reasons (for example, to trigger accessory view actions) or when you want to conditionally allow edits based on runtime logic:

swift
1func textField(
2    _ textField: UITextField,
3    shouldChangeCharactersIn range: NSRange,
4    replacementString string: String
5) -> Bool {
6    guard textField == codeField else { return true }
7    // Only allow input if the user has verified their email
8    return currentUser.isEmailVerified
9}

Overriding inputView for Picker-Only Fields

Sometimes you want the text field to display a value, but instead of the keyboard you want to show a UIPickerView or UIDatePicker. You achieve this by assigning a custom view to the inputView property. The system presents your custom view in place of the keyboard when the field becomes the first responder.

swift
1class DateSelectionViewController: UIViewController {
2
3    @IBOutlet weak var dateField: UITextField!
4
5    private let datePicker = UIDatePicker()
6
7    override func viewDidLoad() {
8        super.viewDidLoad()
9
10        datePicker.datePickerMode = .date
11        datePicker.preferredDatePickerStyle = .wheels
12        datePicker.addTarget(
13            self,
14            action: #selector(dateChanged),
15            for: .valueChanged
16        )
17
18        // Replace the keyboard with the date picker
19        dateField.inputView = datePicker
20
21        // Optional: add a toolbar with a Done button
22        let toolbar = UIToolbar()
23        toolbar.sizeToFit()
24        let doneButton = UIBarButtonItem(
25            barButtonSystemItem: .done,
26            target: self,
27            action: #selector(dismissPicker)
28        )
29        toolbar.setItems([doneButton], animated: false)
30        dateField.inputAccessoryView = toolbar
31    }
32
33    @objc private func dateChanged() {
34        let formatter = DateFormatter()
35        formatter.dateStyle = .medium
36        dateField.text = formatter.string(from: datePicker.date)
37    }
38
39    @objc private func dismissPicker() {
40        dateField.resignFirstResponder()
41    }
42}

Combine this with the delegate's shouldChangeCharactersIn returning false to ensure the user cannot paste text into the field. The field's value should only change through your picker handler.

Common Pitfalls

  • Forgetting to set the delegate: If you rely on shouldChangeCharactersIn but forget to assign textField.delegate = self, the method never fires and the field accepts all input.
  • Using isUserInteractionEnabled when you need copy support: This property blocks every interaction, including text selection. Use the delegate approach instead if the user needs to copy the displayed value.
  • Not providing visual feedback for disabled fields: A field that looks active but ignores taps frustrates users. Always dim the color, change the background, or use isEnabled to leverage the built-in disabled appearance.
  • Leaving the keyboard visible for picker-only fields: If you set inputView to a picker but do not also add an inputAccessoryView with a Done button, the user has no obvious way to dismiss the picker.
  • Blocking paste but not drag-and-drop: On iPad, users can drag text into a field even if shouldChangeCharactersIn returns false. If you truly need to prevent all input, combine the delegate with isUserInteractionEnabled or override paste(_:).

Summary

  • isUserInteractionEnabled = false blocks all interaction, including selection and copy, without changing the field's appearance.
  • isEnabled = false disables the field and applies the standard dimmed look that users expect from inactive controls.
  • The UITextFieldDelegate method shouldChangeCharactersIn lets you selectively block or allow edits while keeping the field interactive for tapping, selecting, and copying.
  • Setting inputView to a UIPickerView or UIDatePicker replaces the keyboard entirely, creating a picker-only field.
  • Choose the approach based on whether you need visual dimming, text selection support, or a custom input mechanism.

Course illustration
Course illustration

All Rights Reserved.