Text selection is a small feature with a large usability impact. Users often need to copy error messages, transaction IDs, URLs, log output, addresses, or a single sentence from a longer block of text.
SwiftUI makes enabling it delightfully small:
Text("Request failed: 401 Unauthorized")
.textSelection(.enabled)
However, this modifier has a behaviour change that matters a lot for compatibility. The same source code does not deliver the same selection experience on every supported iOS release.
The short version
| Platform / version | What .textSelection(.enabled) does |
|---|---|
| macOS 12+ | Lets people select a text range with normal pointer and keyboard conventions. |
| iOS / iPadOS 15 through 26 | Long press exposes a system menu that acts on the whole Text view. No native range handles for selecting only part of that Text. |
| iOS / iPadOS 27+ | Long press shows selection highlight and handles, enabling range selection. |
Apple documents this distinction explicitly. The modifier has been available since iOS 15, yet the familiar partial-selection interaction only arrives in iOS 27. That is a frustrating gap for something as basic as selecting two words in a paragraph. Come on, Apple: SwiftUI should not force a UIKit escape hatch for a fundamental text interaction after so many years.
The iOS 27 row reflects Apple’s current documentation. Test it on the target OS and Xcode you are shipping with; do not infer the behaviour just from the modifier compiling.
What SwiftUI gets right
One clear, composable API
VStack(alignment: .leading) {
Text("Build failed")
.font(.headline)
Text(logOutput)
.font(.system(.body, design: .monospaced))
}
.textSelection(.enabled)
Applying the modifier to a container can enable selection for the contained Text views. That is clean, discoverable SwiftUI code with no subclassing or delegate plumbing.
Great for whole-value copying
On iOS 15–26, the behaviour is still useful when the entire value is what users want: a UUID, an email address, an API key displayed safely, an error message, or an IP address. Apple’s Human Interface Guidelines specifically calls out useful labels such as error messages, locations, and IP addresses as candidates for copyability.
Native accessibility and platform conventions
SwiftUI hands the interaction to the system, which is generally a good default. On macOS in particular, .textSelection(.enabled) feels natural immediately.
Where SwiftUI Text falls short
1. Partial selection on iOS was missing until iOS 27
For a paragraph, log, or legal text, users commonly want only a phrase. On iOS 26 and earlier, SwiftUI treats a selectable Text as a whole-value copy target. There are no selection handles to adjust the range.
This is the central limitation. The modifier can make an app look like it supports selection while delivering a less capable experience on most deployed versions.
2. No selection inside Button
Apple documents that Button views do not support text selection. If a piece of text needs both a tap action and copyable text, redesign the interaction or use a separate control instead of expecting .textSelection to solve both jobs.
3. Limited control over the interaction
Text exposes an opt-in switch, not a text-engine configuration surface. If the product needs precise selection behaviour, custom menus, programmatic ranges, selection-state observation, or highly custom rich-text interaction, SwiftUI’s simple modifier can become too restrictive.
SwiftUI Text versus UIKit UITextView
The useful UIKit comparison is UITextView, not UILabel.
UITextView is a full text component. For read-only selectable content, configure it with isEditable = false and isSelectable = true. It has long supplied UIKit’s standard range-selection UI: selection highlight, drag handles, the loupe in long text, and copy actions.
Unlike Text, it is imperative and heavier. In SwiftUI, it needs a UIViewRepresentable bridge; its container, scrolling, sizing, and accessibility need careful integration. But when the requirement is “select part of this text” on iOS 15–26, it is the reliable native answer.
UILabel is worth mentioning only to avoid a common misconception: it is a display view and has no native selectable-text API. Do not use it as the selection fallback.
| Capability | SwiftUI Text
|
UIKit UITextView (read-only) |
|---|---|---|
| Display static text | Excellent | Good, but heavier |
| Enable copy with a small API | Yes: .textSelection(.enabled)
|
Yes: configure properties |
| Range selection on iOS 26 and earlier | No, whole Text action only |
Yes |
| Rich attributed content | Improving, but intentionally higher-level | Strong interaction + display support |
| Selection handles / loupe / standard editing mechanics | iOS 27+ for Text ranges |
Yes |
| Custom selection interaction | Limited | Broad UIKit control; can go further with UITextInteraction
|
| SwiftUI layout ergonomics | Excellent | Requires a wrapper |
So the relevant decision is Text vs a read-only UITextView.
The UIKit fallback for older iOS versions
When range selection is a requirement before iOS 27, bridge a non-editable UITextView into SwiftUI:
import SwiftUI
import UIKit
struct SelectableTextView: UIViewRepresentable {
let attributedText: NSAttributedString
func makeUIView(context: Context) -> UITextView {
let textView = UITextView()
textView.isEditable = false
textView.isSelectable = true
textView.isScrollEnabled = false
textView.backgroundColor = .clear
textView.textContainerInset = .zero
textView.textContainer.lineFragmentPadding = 0
textView.adjustsFontForContentSizeCategory = true
return textView
}
func updateUIView(_ textView: UITextView, context: Context) {
textView.attributedText = attributedText
}
}
Usage:
SelectableTextView(
attributedText: NSAttributedString(
string: longReleaseNote,
attributes: [
.font: UIFont.preferredFont(forTextStyle: .body),
.foregroundColor: UIColor.label
]
)
)
UITextView has more layout and accessibility details to verify than Text: Dynamic Type, text-container sizing, links, scrolling, ScrollView nesting, and content compression. It is not as elegant, but it uses the mature UIKit text system that already supplies standard selection UI for native text views.
For custom UIKit text components, UITextInteraction can provide the system’s non-editable selection behaviour, including the selection UI and gestures, as long as the custom view implements the required text-input machinery.
A pragmatic compatibility strategy
Choose the implementation based on the user task, not ideology:
if #available(iOS 27.0, *) {
Text(articleBody)
.textSelection(.enabled)
} else {
SelectableTextView(
attributedText: NSAttributedString(string: articleBody)
)
}
Use this strategy only when partial selection is a real requirement. A UITextView bridge is unnecessary complexity for a one-line order ID where copying the entire value is correct.
Decision guide
-
Short, whole-value content: use
Textwith.textSelection(.enabled). - macOS app: native SwiftUI text selection is usually the simplest choice.
-
Long text where iOS 15–26 users must select a phrase: use a read-only
UITextViewwrapper. -
Custom interaction or selection menus: start from UIKit; evaluate
UITextInteractionifUITextViewis not enough. - Text inside a button: separate the button action from the copyable text.
Final thought
SwiftUI’s API is wonderfully small, and that is exactly why many teams reach for it first. But simplicity is only a win when the behaviour meets the platform expectation. Until iOS 27, .textSelection(.enabled) on iPhone is closer to “make this whole value copyable” than “let the user select text.”
That distinction belongs in product requirements, compatibility testing, and code review. Apple has finally closed the gap in the documented iOS 27 behaviour—but it took far too long for such a fundamental capability.

Top comments (0)