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 sampleTo 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)


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
}
}


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.