This subchapter is provided as a free sample for SwiftUI Fundamentals book.

You can read this subchapter online or download the sample bundle with PDF and EPUB by clicking the link below.

Download free sample

To get access to the contents of the whole book you need to purchase a copy.

FREE SAMPLE - online version

Text initializers and contextual behavior

When we talk about text in SwiftUI, we might immediately think of the Text view, which explicitly displays non-editable text to the user. However, many built-in SwiftUI components also include text elements. When we initialize common views and controls, we often provide a label, a string, or a string literal. Passing a string is simply a convenience for creating a Text label for the control. Since these labels are Text views internally, all styling and localization techniques that apply to standalone Text views also apply to control labels.

Like all SwiftUI views, Text is a struct. It stores information internally and resolves that information into a string at render time. The final string that appears on the screen depends on how we create the text and the context in which it is placed.

For example, if we initialize a Text view and assign to a variable, it remains unresolved until it's added to the view hierarchy.

let movieTitle = Text("How to Train Your Dragon")

To be rendered as a string on screen, Text requires an environment. Some of this environment may be defined by developers using view modifiers and environment values, while other parts are determined by SwiftUI itself based on the textโ€™s placement. Device settings, such as dark mode, accessibility text size, and locale, will also impact how Text is resolved.

SwiftUI automatically adapts text styling based on the environment it inherits. For example, inserting the movieTitle text into a VStack and applying a red foreground style to the hierarchy results in it being displayed in red.

VStack(spacing: 12) {
    movieTitle
    Text("๐Ÿฟ๐Ÿฟ๐Ÿฟ๐Ÿฟ๐Ÿฟ๐Ÿฟ")
}
.foregroundStyle(.red)
Text reading 'How to Train Your Dragon' in red, displayed above six popcorn emoji Text reading 'How to Train Your Dragon' in red, displayed above six popcorn emoji

However, the same movieTitle text behaves differently when placed inside a Link. If no explicit foreground style is applied, SwiftUI automatically styles it using the default link color.

Link(destination: trailerURL) {
    HStack {
        Text("๐ŸŽฅ")
        movieTitle
    }
}
A movie camera emoji next to the text 'How to Train Your Dragon' in blue A movie camera emoji next to the text 'How to Train Your Dragon' in blue

Even the actual string that is displayed can change based on the localization settings of the device.

# Choosing the right Text initializer

So far, we know that the Text struct stores data and resolves it into a string at render time. The way this data is stored directly impacts how it is rendered. SwiftUI provides multiple initializers for Text, it can be created from a string literal or variable, a date with a specified format, an image, or an attributed string. Choosing the right initializer helps prevent unexpected behavior.

One of the most subtle but crucial differences in text initialization is between using a string variable and a string literal. Consider the following:

let favoriteMovie = "The Lion King"
Text(favoriteMovie)

Text("The Lion King")

These two examples seem identical, but SwiftUI treats them differently. When Text is initialized with a string variable, the framework calls the generic initializer that accepts a value conforming to StringProtocol. This means SwiftUI stores the text as a standard Swift String. However, when Text is initialized with a string literal, SwiftUI uses the LocalizedStringKey initializer. The LocalizedStringKey type conforms to ExpressibleByStringLiteral, and it takes priority over the StringProtocol initializer. SwiftUI assumes that string literals should be localized.

The path SwiftUI follows to resolve text into a string differs based on the initializer used. If Text stores a String, the framework displays it as-is without looking for localization. If Text stores a LocalizedStringKey, SwiftUI searches for a translation in the main bundle. If it doesn't find the appropriate localization, it falls back to displaying the key itself.

If we are not localizing the app, we might not notice the difference in behavior immediately. However, understanding this distinction is crucial to avoid surprises, as LocalizedStringKey has additional functionality. For example, LocalizedStringKey supports interpolating more types, such as images and dates, and also parses Markdown, enabling richer text rendering directly within SwiftUI.