Text
composition in SwiftUI can often be cumbersome, especially when there's logic affecting its format and content.
TextBuilder leverages the power of Swift Macros to solve this problem. The @TextBuilder
macro transforms functions into builder-style closures, making text composition intuitive and readable.
Add TextBuilder
to your Swift Package Manager dependencies:
.package(url: "https://github.com/davdroman/swiftui-text-builder", from: "4.0.0"),
Then, add the dependency to your desired target:
.product(name: "TextBuilder", package: "swiftui-text-builder"),
Apply @TextBuilder
to functions that return Text
. The macro will transform the function body into a builder-style closure that concatenates text segments.
@TextBuilder
func loremIpsum() -> Text {
Text("Lorem").underline().foregroundColor(.blue)
Text("ipsum dolor")
Text("sit").bold()
Text("amet, consectetur")
}
This creates a concatenated Text
without any separators between segments.
You can specify a separator to be inserted between text segments:
@TextBuilder(separator: " ")
func spacedText() -> Text {
Text("Lorem").underline().foregroundColor(.blue)
Text("ipsum dolor")
Text("sit").bold()
Text("amet, consectetur")
}
For multiline text:
@TextBuilder(separator: "\n")
func multilineText() -> Text {
Text("Lorem").underline().foregroundColor(.blue)
Text("ipsum dolor")
Text("sit").bold()
Text("amet, consectetur")
}
TextBuilder accepts String
types directly and provides a convenient .text
computed property:
@TextBuilder(separator: " ")
func mixedText() -> Text {
"Hello" // String literal becomes verbatim Text
"world".text.bold() // Use .text for chaining modifiers
String(2025) // Any StringProtocol works
}
TextBuilder supports Swift's control flow statements:
@TextBuilder(separator: " ")
func conditionalText(showDetails: Bool) -> Text {
"Hello"
if showDetails {
"with details"
} else {
"basic"
}
if let name = userName {
name.text.italic()
}
for i in 1...3 {
String(i)
}
}
If you prefer not to use macros, you can use the underlying Text
initializer directly:
var body: some View {
Text(separator: " 👏 ") {
"Lorem".text.underline().foregroundColor(.blue)
"ipsum dolor"
"sit".text.bold()
"amet, consectetur"
}
}
This is useful if you simply want to insert some rich text into a view body without defining a separate function.
The @TextBuilder
macro currently cannot be applied to computed properties due to Swift limitations. Use functions instead.
See Swift Issue #75715 for updates on computed property support.