SwiftUI builds UI by taking a simple view and chaining Modifiers to it.
Understanding how modifiers work under the hood, and how SwiftUI compiles multiple views together using ViewBuilder, is key to mastering the framework.
Every time you apply a modifier to a view in SwiftUI, it actually wraps the previous view in a brand new hidden container view.
Because of this, the order in which you write your modifiers fundamentally changes how the UI looks.
import SwiftUIstruct OrderMattersView: View { var body: some View { VStack(spacing: 30) { // Example 1: Background THEN Padding Text("Hello!") .background(Color.blue) .padding() // Example 2: Padding THEN Background Text("World!") .padding() .background(Color.red) } } }
In Example 1, the blue background only covers the text itself. In Example 2, the padding expands the view first, so the red background colors the entire padded box!
If you find yourself applying the exact same 5 modifiers to dozens of text elements, you should create a Custom ViewModifier.
This keeps your code DRY (Don't Repeat Yourself) and highly readable.
// 1. Define the modifier
struct PrimaryLabel: ViewModifier {
func body(content: Content) -> some View {
content
.padding()
.background(Color.blue)
.foregroundColor(.white)
.font(.headline)
.cornerRadius(10)
}
}
// 2. Create an extension for cleaner syntax
extension View {
func primaryStyle() -> some View {
self.modifier(PrimaryLabel())
}
}
// 3. Use it!
// Text("Submit").primaryStyle()
You might wonder how a VStack can accept 10 different Text views inside its curly braces without an array or commas.
This works via a Swift feature called @ViewBuilder.
It is a result builder that automatically combines multiple views into a single composite view (a TupleView). You can use this attribute on your own functions to cleanly return varying views!
If you want a blue box with space inside it around the text, what is the correct order of modifiers?