UITextView
character limit
iOS development
Swift programming
text input restrictions

Limit number of characters in uitextview

Master System Design with Codemia

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

Introduction

To limit the number of characters in a UITextView, intercept edits through the delegate and decide whether the proposed change should be accepted. The key detail is that you must compute the resulting text after the edit, not just check the current text length.

Use shouldChangeTextIn in the Delegate

The standard place to enforce a limit is the delegate method textView(_:shouldChangeTextIn:replacementText:).

swift
1import UIKit
2
3final class ViewController: UIViewController, UITextViewDelegate {
4    @IBOutlet weak var textView: UITextView!
5    let limit = 140
6
7    override func viewDidLoad() {
8        super.viewDidLoad()
9        textView.delegate = self
10    }
11
12    func textView(_ textView: UITextView,
13                  shouldChangeTextIn range: NSRange,
14                  replacementText text: String) -> Bool {
15        guard let current = textView.text,
16              let stringRange = Range(range, in: current) else {
17            return false
18        }
19
20        let updated = current.replacingCharacters(in: stringRange, with: text)
21        return updated.count <= limit
22    }
23}

This handles typing, deletion, and replacement in one place.

Why Range Conversion Matters

UITextView gives you an NSRange, but Swift strings are Unicode-aware. Converting the range properly is important, especially when the text contains emoji or other multi-scalar characters.

That is why the Range(range, in: current) conversion is safer than trying to slice by integer offsets manually.

Update a Counter Label at the Same Time

In real apps, users usually benefit from a remaining-character counter.

swift
1func textViewDidChange(_ textView: UITextView) {
2    let remaining = limit - textView.text.count
3    counterLabel.text = "\(remaining)"
4}

The delegate check enforces the rule, and the counter makes the rule visible.

Be Careful With Pasting and Marked Text

Character limits are not only about keyboard typing. Pasting large text can exceed the limit in one action, so the delegate check must handle replacement text of any size.

If you support complex input methods, also remember that temporary marked text during composition can make editing behavior more subtle. Test with real keyboards and languages, not only with simple Latin typing.

If You Need Truncation Instead of Rejection

Some apps prefer to accept the paste but truncate the final text.

swift
1func textViewDidChange(_ textView: UITextView) {
2    if textView.text.count > limit {
3        textView.text = String(textView.text.prefix(limit))
4    }
5}

This is a different user experience from rejecting the change upfront. Use it only if that behavior is intentional.

Decide Whether Hard Blocking or Soft Feedback Is Better

Some apps should block extra input immediately. Others should let the user keep editing temporarily and show a counter or validation message. The technical implementation is different, but the real decision is product behavior rather than delegate syntax alone.

Keep the UX Consistent With Validation Elsewhere

If the same field is also validated on the backend, make sure the frontend character limit matches the server rule. Mismatched limits create confusing bugs where the UI accepts text that the API later rejects, or vice versa.

Test With Real Copy and Paste Behavior

Typing one character at a time is the easy case. Paste operations are where many length-limit implementations show their real behavior, so they should be part of the normal test path.

Common Pitfalls

The biggest mistake is checking only textView.text.count before the edit instead of calculating the post-edit result.

Another issue is forgetting about paste operations, which can add many characters at once.

A third problem is mishandling Unicode by working with raw integer indexes instead of converting the range safely.

Summary

  • Use textView(_:shouldChangeTextIn:replacementText:) to enforce a character limit.
  • Compute the resulting text after the proposed change, not just the current length.
  • Convert NSRange safely into a Swift string range.
  • Test with paste operations and non-trivial Unicode input.
  • Pair the limit with a visible counter when user experience matters.

Course illustration
Course illustration

All Rights Reserved.