Swift
UITextView
Placeholder Text
iOS Development
Programming Tips

Add placeholder text inside UITextView in Swift?

Master System Design with Codemia

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

Introduction

UITextView does not provide a built-in placeholder property like UITextField, so you have to implement the behavior yourself. The most reliable approach is to add a label inside the text view, keep its styling aligned with the text view’s font and insets, and hide or show it when the text changes.

Why A Label Is The Best Approach

Some quick solutions fake a placeholder by setting the text view’s text property to a light-gray string and clearing it when editing begins. That works at first, but it complicates real text handling because the placeholder becomes mixed with actual content.

A separate UILabel avoids that problem entirely:

  • the placeholder is presentation only
  • the real text remains real user input only
  • styling and layout stay easier to control

A Reusable UITextView Subclass

A subclass gives you one component you can reuse anywhere.

swift
1import UIKit
2
3final class PlaceholderTextView: UITextView {
4    private let placeholderLabel = UILabel()
5
6    var placeholder: String = "" {
7        didSet {
8            placeholderLabel.text = placeholder
9        }
10    }
11
12    override var text: String! {
13        didSet {
14            updatePlaceholderVisibility()
15        }
16    }
17
18    override var font: UIFont? {
19        didSet {
20            placeholderLabel.font = font
21        }
22    }
23
24    override init(frame: CGRect, textContainer: NSTextContainer?) {
25        super.init(frame: frame, textContainer: textContainer)
26        configurePlaceholder()
27    }
28
29    required init?(coder: NSCoder) {
30        super.init(coder: coder)
31        configurePlaceholder()
32    }
33
34    private func configurePlaceholder() {
35        placeholderLabel.textColor = .placeholderText
36        placeholderLabel.numberOfLines = 0
37        placeholderLabel.font = font
38        addSubview(placeholderLabel)
39
40        NotificationCenter.default.addObserver(
41            self,
42            selector: #selector(textDidChangeNotification),
43            name: UITextView.textDidChangeNotification,
44            object: self
45        )
46
47        updatePlaceholderVisibility()
48    }
49
50    override func layoutSubviews() {
51        super.layoutSubviews()
52        let x = textContainerInset.left + 5
53        let y = textContainerInset.top
54        let width = bounds.width - x - textContainerInset.right - 5
55        placeholderLabel.frame = CGRect(x: x, y: y, width: width, height: 0)
56        placeholderLabel.sizeToFit()
57    }
58
59    @objc private func textDidChangeNotification() {
60        updatePlaceholderVisibility()
61    }
62
63    private func updatePlaceholderVisibility() {
64        placeholderLabel.isHidden = !text.isEmpty
65    }
66
67    deinit {
68        NotificationCenter.default.removeObserver(self)
69    }
70}

This keeps the placeholder behavior independent of the stored text value.

Using The Subclass

Once the subclass exists, usage is simple.

swift
let textView = PlaceholderTextView()
textView.font = .systemFont(ofSize: 16)
textView.placeholder = "Enter your notes here"

If you create it in Interface Builder, the subclass still works because the initializer and notification setup are handled in both code paths.

Why layoutSubviews Matters

The placeholder position must respect the text view’s content insets and width. If you set the label frame only once during initialization, it can be wrong after Auto Layout resizes the text view.

Using layoutSubviews ensures the placeholder moves correctly when:

  • the device rotates
  • dynamic type changes font size
  • the text view frame changes through constraints

Styling Considerations

To make the placeholder feel native:

  • match the text view font
  • use .placeholderText or a light gray color
  • respect textContainerInset
  • update layout when fonts or bounds change

Those details matter more than the basic hide-show logic.

Common Pitfalls

The most common mistake is storing the placeholder string directly in text. That makes placeholder state indistinguishable from user input and complicates validation, saving, and accessibility.

Another mistake is forgetting to update the placeholder layout after Auto Layout changes the text view size.

A third issue is not removing the notification observer in custom reusable components, which can create lifecycle bugs in older observer patterns.

Summary

  • 'UITextView has no built-in placeholder support.'
  • A child UILabel is the cleanest implementation strategy.
  • Keep the placeholder separate from the real text value.
  • Update placeholder visibility on text changes and layout on size changes.
  • A small reusable subclass gives the most maintainable solution.

Course illustration
Course illustration

All Rights Reserved.