How to add a placeholder to UITextView in Swift: a complete guide

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Why UITextView doesn't have a built-in placeholder and how to work around it

\n\n

Every iOS developer who has worked with UITextView at least once has encountered the same problem: unlike UITextField, UITextView does not have a built-in placeholder property. You create a multi-line text input field, run the app — and see an empty white rectangle. The user doesn't understand what to enter there, and the designer is outraged.

\n\n

Why didn't Apple add this property? Historically, UITextView was positioned as an element for displaying and editing large volumes of text (e.g., notes or emails), rather than as an input field with a hint. But times have changed: today we use UITextView for comments, descriptions, biographies — everywhere a placeholder is needed.

\n\n

In this article, we'll cover 3 proven ways to add placeholder text inside UITextView in Swift. You'll learn how to do it via UILabel, via NSAttributedString attributes, and by creating your own subclass. Let's go!

\n\n

Method 1: Classic UILabel on top of UITextView

\n\n

The simplest and most straightforward way is to place a UILabel on top of UITextView and manage its visibility. This method is ideal for beginners and for projects that don't require complex customization.

\n\n

How it works

\n\n

You add a UILabel as a child element of UITextView, set its placeholder text, and hide it when the user starts typing. Here's a step-by-step example:

\n\n
import UIKit\n\nclass ViewController: UIViewController, UITextViewDelegate {\n    \n    @IBOutlet weak var textView: UITextView!\n    let placeholderLabel = UILabel()\n    \n    override func viewDidLoad() {\n        super.viewDidLoad()\n        textView.delegate = self\n        setupPlaceholder()\n    }\n    \n    func setupPlaceholder() {\n        placeholderLabel.text = "Enter your comment..."\n        placeholderLabel.font = UIFont.systemFont(ofSize: 16)\n        placeholderLabel.textColor = UIColor.lightGray\n        placeholderLabel.translatesAutoresizingMaskIntoConstraints = false\n        textView.addSubview(placeholderLabel)\n        \n        NSLayoutConstraint.activate([\n            placeholderLabel.topAnchor.constraint(equalTo: textView.topAnchor, constant: 8),\n            placeholderLabel.leadingAnchor.constraint(equalTo: textView.leadingAnchor, constant: 5),\n            placeholderLabel.trailingAnchor.constraint(equalTo: textView.trailingAnchor, constant: -5)\n        ])\n    }\n    \n    func textViewDidChange(_ textView: UITextView) {\n        placeholderLabel.isHidden = !textView.text.isEmpty\n    }\n}
\n\n

Important: don't forget to set the UITextViewDelegate delegate and implement the textViewDidChange method. If you are using SwiftUI, the approach will be different — there, the .overlay modifier is used.

\n\n

Pros and cons

\n
    \n
  • Pros: simplicity, easy to understand, works on any iOS version.
  • \n
  • Cons: you need to monitor constraints if the textview's insets change. Also, it won't work if the textview has an NSAttributedString with different alignments.
  • \n
\n\n

Method 2: Placeholder via NSAttributedString

\n\n

A more elegant way is to use string attributes. The idea is that you show the placeholder as attributed text in gray color, and when the user starts typing, you replace it with regular text.

\n\n

This method is especially useful if you are working with UITextView in Swift and don't want to bother with additional views.

\n\n

Implementation

\n\n
import UIKit\n\nclass ViewController: UIViewController, UITextViewDelega                

Blogs

Book Recommendations