iOS
UITextView
UILabel
clickable links
duplicate

iOS UITextView or UILabel with clickable links to actions

Master System Design with Codemia

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

Introduction

If you need clickable links inside a block of text on iOS, UITextView is usually the right tool. A UILabel can handle whole-label taps easily, but once you need multiple independent tappable ranges inside one sentence, UITextView saves you from reimplementing text layout and hit testing yourself.

Why UITextView Is Usually the Better Fit

UITextView already supports attributed strings with .link attributes. It also gives you delegate callbacks when a user taps one of those links.

That means you get:

  • multiple tappable ranges in one text block
  • built-in handling of attributed links
  • a straightforward delegate hook for custom app actions

A minimal example:

swift
1import UIKit
2
3final class ViewController: UIViewController, UITextViewDelegate {
4    override func viewDidLoad() {
5        super.viewDidLoad()
6        view.backgroundColor = .systemBackground
7
8        let textView = UITextView(frame: CGRect(x: 20, y: 100, width: 320, height: 120))
9        textView.isEditable = false
10        textView.isScrollEnabled = false
11        textView.backgroundColor = .clear
12        textView.delegate = self
13
14        let text = NSMutableAttributedString(string: "Read our Terms and Privacy Policy")
15        text.addAttribute(.link, value: "app://terms", range: NSRange(location: 9, length: 5))
16        text.addAttribute(.link, value: "app://privacy", range: NSRange(location: 19, length: 14))
17
18        textView.attributedText = text
19        view.addSubview(textView)
20    }
21
22    func textView(_ textView: UITextView,
23                  shouldInteractWith URL: URL,
24                  in characterRange: NSRange,
25                  interaction: UITextItemInteraction) -> Bool {
26        if URL.absoluteString == "app://terms" {
27            print("open terms")
28            return false
29        }
30        if URL.absoluteString == "app://privacy" {
31            print("open privacy")
32            return false
33        }
34        return true
35    }
36}

This is the standard pattern for inline clickable ranges.

UILabel Is Better for Simpler Tap Behavior

If the whole piece of text acts like one tap target, a UILabel plus a gesture recognizer is much simpler.

swift
1import UIKit
2
3final class LabelViewController: UIViewController {
4    override func viewDidLoad() {
5        super.viewDidLoad()
6
7        let label = UILabel(frame: CGRect(x: 20, y: 100, width: 260, height: 40))
8        label.text = "Tap here to learn more"
9        label.textColor = .systemBlue
10        label.isUserInteractionEnabled = true
11
12        let tap = UITapGestureRecognizer(target: self, action: #selector(labelTapped))
13        label.addGestureRecognizer(tap)
14
15        view.addSubview(label)
16    }
17
18    @objc private func labelTapped() {
19        print("label tapped")
20    }
21}

This is fine when you only need one action for the whole label.

A label does not naturally tell you which character range was tapped. To build true inline-link behavior in a UILabel, you need to map touch coordinates back to text layout positions yourself.

That usually means extra work with text layout machinery, including:

  • measuring glyph positions
  • mapping taps to character indices
  • handling line breaks and truncation
  • keeping interaction logic in sync with attributed text styling

It is possible, but it is much more work than using UITextView.

Making UITextView Feel Like Static Text

Some developers avoid UITextView because they do not want it to feel like an editable text field. That is easy to solve.

Useful settings are:

  • 'isEditable = false'
  • 'isScrollEnabled = false'
  • 'backgroundColor = .clear'
  • adjust insets if needed for tighter layout

With those settings, a text view can behave visually much like a label while still giving you built-in link interaction.

Custom URL Schemes Work Well for Actions

Notice that the example used app://terms instead of an external web URL. That is a good pattern when the tap should trigger in-app navigation or a custom action.

The delegate can inspect the URL and decide whether to:

  • open an internal screen
  • present a modal
  • open Safari for a real web link

That keeps link ranges simple while giving you flexible action handling.

Common Pitfalls

The biggest mistake is choosing UILabel for multiple inline links and then having to build custom touch detection that UITextView already provides.

Another common issue is forgetting to disable editing on the text view. A tappable legal-text block should not behave like an editor.

Developers also sometimes add a gesture recognizer to a label and assume it can distinguish multiple ranges automatically. It cannot without extra layout logic.

Finally, if you use custom URL values for app actions, handle them consistently in the delegate instead of mixing several ad hoc approaches.

Summary

  • Use UITextView when you need real inline clickable links in one text block.
  • Use UILabel only when the interaction is coarse-grained or the whole label acts as one tap target.
  • Style UITextView to look like static text if needed.
  • Custom URL values are a clean way to map link taps to app actions.
  • 'UILabel becomes expensive to maintain once you need per-range link behavior.'

Course illustration
Course illustration

All Rights Reserved.