SwiftUI Internals: Understanding @ViewBuilder and ViewModifier
Let’s start to clear all the doubts and understand why/when we need to use these powerful UI concepts.

SwiftUI Internals: Understanding @ViewBuilder and ViewModifier
Let’s start to clear all the doubts and understand why/when we need to use these powerful UI concepts.
Start from @ViewBuilder
@ViewBuilder is a Result Builder used by SwiftUI to allow multiple child views inside a closure.
Confused …😕, Let’s explore.

In the above code return statement is missing, but where are you going to add the return, if you choose Text(“A”) → Text(“B”) will be abandon. If you choose Text(“B”) → Text(“A”) will be abandon.
Two have both the Text view you need to either add inside VStack, HStack or similar container view but these container come with modifiers to apply design.
To solve this @ViewBuilder introduced, which add these views like as stack and bind in single view. 🙌 ……Error gone

A simple view binder which stitch all views that is present in closure irrespective of any view type.
@ViewBuilder Is NOT Runtime Magic
@ViewBuilder is:
- NOT reflection
- NOT XML rendering
- NOT runtime parsing
It is a: Compile-time transformation
Swift rewrites:
@ViewBuilder
var body: some View {
Text("A")
Text("B")
}
into something conceptually like:
ViewBuilder.buildBlock(
Text("A"),
Text("B")
)
What is ViewBuilder Internally?
ViewBuilder itself is a type marked with:
@resultBuilder
struct ViewBuilder { }
The @resultBuilder attribute tells Swift:
“This type can transform closure syntax into builder method calls.”
Why Do We Use @?
This is a common confusion. ViewBuilder is a TYPE.
@ViewBuilder becomean ATTRIBUTE.
The @ syntax tells the compiler:
“Apply special transformation behaviour here.”
>> Core Builder Functions
A Result Builder uses special static methods.
buildBlock: Combines multiple views.
Text("A")
Text("B")
// becomes
buildBlock(
Text("A"),
Text("B")
)
buildEither: Handles if/else.
if isLoggedIn {
HomeView()
} else {
LoginView()
}
buildOptional: Handles optional branches.
if let user = user {
Text(user.name)
}
buildArray: Handles loops.
👋 HOPE … till here some concepts must be build up.
var body: some View {}
body: is a backed by @ViewBuilder

Before iOS 14.0 body through error if you write like this
var body: some View {
Text("A")
Text("B")
}
1. @ViewBuilder — Using as a Components
One of the most common use cases.
struct CardView<Content: View>: View {
let content: Content
init(
@ViewBuilder content: () -> Content
) {
self.content = content()
}
var body: some View {
VStack {
content
}
.padding()
.background(Color.gray.opacity(0.1))
.cornerRadius(12)
}
}
--------------------------------
Uses:
var body: some View {
CardView {
Text("Hello")
Image(systemName: "star.fill")
}
}
Why This Fails Without @ViewBuilder
Without builder:
init(content: () -> Content)
This fails:
CardView {
Text("Hello")
Image(systemName: "star")
}
Because normal closures can only return ONE expression.
Can This Still Works Without Builder
Yes… just need to wrap in VStack or any other container.
CardView {
VStack {
Text("Hello")
Image(systemName: "star")
}
}
Because closure returns ONE view: VStack
Variadic Parameters and SwiftUI
SwiftUI builders heavily rely on concepts similar to variadic parameters.
Example:
func log(_ items: String...) {
print(items)
}
------------------------ Usage-------------
log("A", "B", "C")
Internally Swift converts them into arrays.
Why Variadics Exist
Mainly for:
- cleaner APIs
- DSL readability
- builder syntax
- ergonomic call sites
2. @ViewBuilder —Usingwith function
Basic Example
@ViewBuilder
func content() -> some View {
Text("Hello")
Image(systemName: "star")
}
This works because @ViewBuilder allows:
- multiple views
- conditionals
- optional branches
inside the function body.
Without @ViewBuilder
func content() -> some View {
Text("Hello")
Image(systemName: "star") // ❌ Error
}
Normal functions can only return ONE expression.
Can I make content optional 🙋
let content: Content
Yes — but not directly as:
let content: Content?
because Content already conforms to View, and SwiftUI’s generic view system is designed around concrete view types, not optional generic view storage.
This usually creates problems like:
Type 'Content?' does not conform to 'View'
Correct Ways to Make Content Optional
1. Best SwiftUI Way → Use EmptyView
A standard SwiftUI pattern.
struct Card<Content: View>: View {
let content: Content
init(@ViewBuilder content: () -> Content = { EmptyView() }) {
self.content = content()
}
var body: some View {
VStack {
content
}
}
}
Usage:
Card()
--------------------- OR -------------------------------
Card {
Text("Hello")
}
Why This Works
EmptyView is still a valid View.
So Swift infers:
Content == EmptyView
instead of Optional<Content>.
This is how many Apple APIs behave internally.
2. Optional Generic Using Conditional Rendering
Possible, but ugly and rarely used.
struct Card<Content: View>: View {
let content: Content?
var body: some View {
VStack {
if let content {
content
}
}
}
}
But this has problems:
- Optional generic complexity
- Type inference issues
- Harder APIs
- Less SwiftUI-idiomatic
❌ Usually avoided.
3. Multiple Initialisers
Very common in SwiftUI internals.
struct Card<Content: View>: View {
let content: Content?
init() where Content == EmptyView {
self.content = EmptyView()
}
init(@ViewBuilder content: () -> Content) {
self.content = content()
}
var body: some View {
VStack {
content
}
}
}
Usage:
Card()
--------------------- OR -------------------------------
Card {
Text("Hello")
}
Why Apple Prefers EmptyView
SwiftUI is heavily generic + compile-time optimised.
Optional views:
Content?
introduce:
- extra enum wrapping
- conditional rendering paths
- more type complexity
EmptyView is:
- zero-cost
- Optimised
- compile-time friendly
- identity-safe for diffing
Important Interview Knowledge
Optional<View> vs EmptyView
SwiftUI internally prefers:
EmptyView
NOT:
nil
because SwiftUI’s rendering system works best with concrete types.
Example from SwiftUI APIs
Many APIs conceptually behave like:
Section {
Text("Content")
} header: {
EmptyView()
}
instead of:
header: nil
Advanced Generic Insight
This works:
Card<EmptyView>()
because:
EmptyView: View
and Swift resolves generic specialisation at compile time.
Most Idiomatic Production Solution
struct Card<Content: View>: View {
let content: Content
init(
@ViewBuilder content: () -> Content = { EmptyView() }
) {
self.content = content()
}
var body: some View {
VStack {
content
}
}
}
This is:
- clean
- performant
- SwiftUI-native
- interview-quality
- Apple-style API design
Common SwiftUI Usage
1. Reusable UI Functions
@ViewBuilder
func profileSection() -> some View {
Text("Medium")
.font(.title)
Text("SwiftUI Concepts")
.foregroundColor(.gray)
}
Usage:
VStack {
profileSection()
}
2. Conditional UI
@ViewBuilder
func statusView(isPremium: Bool) -> some View {
if isPremium {
Text("Premium User")
} else {
Text("Free User")
}
}
3. Returning Different View Types
Without builder:
------------------------------------------------------------------------------
func badge(flag: Bool) -> some View {
if flag {
Text("Admin")
} else {
Image(systemName: "person")
}
}
------------------------------------------------------------------------------
❌ Fails because return types differ.
With builder:
------------------------------------------------------------------------------
@ViewBuilder
func badge(flag: Bool) -> some View {
if flag {
Text("Admin")
} else {
Image(systemName: "person")
}
}
------------------------------------------------------------------------------
✅ Works.
When Should You Use @ViewBuilder on Functions?
Use it when function:
- returns UI
- contains multiple views
- contains conditionals
- creates reusable view fragments
Photo by Steve A Johnson on Unsplash
Now — — shift gear towards to ViewModifier
What is ViewModifier?
ViewModifier is a protocol and SwiftUI’s reusable styling/composition mechanism.
Instead of repeating:
Text("Hello")
.padding()
.background(Color.blue)
You encapsulate it.
Basic Custom Modifier
struct PrimaryButtonModifier: ViewModifier {
func body(content: Content) -> some View {
content
.padding()
.background(Color.blue)
.foregroundColor(.white)
.cornerRadius(12)
}
}
------------------------------ Usage ------------------------------------
Text("Login")
.modifier(PrimaryButtonModifier())
Better API Style
SwiftUI-style APIs use extensions.
extension View {
func primaryButtonStyle() -> some View {
modifier(PrimaryButtonModifier())
}
}
------------------------------ Usage ------------------------------------
Text("Login")
.primaryButtonStyle()
Modifier Order Matters: This is extremely important.
Example 1
Text("Hello")
.background(Color.red)
.padding()
Example 2
Text("Hello")
.padding()
.background(Color.red)
Different result.
Why? — — — — — Because every modifier creates a NEW wrapper view.
Why There Is No @ViewModifier 🤔 … Because
ViewModifier is NOT a compiler feature.
It’s just a normal protocol:
protocol ViewModifier
Unlike:
@ViewBuilder@State@Binding
which require compiler transformations.

The Most Important Distinction
@ViewBuilder
→ Creates the view tree
ViewModifier
→ Transforms the view tree
Photo by Roberto Sorin on Unsplash
Now — — Let’s talk about Group
Conceptually SwiftUI’s Group looks like:
struct Group<Content: View>: View {
let content: Content
init(
@ViewBuilder content: () -> Content
) {
self.content = content()
}
var body: some View {
content
}
}
So:
Group {
Text("A")
Text("B")
}
works because:
Groupinitializer accepts a@ViewBuilder- builder combines child views
What Group Actually Does
Group is basically: A transparent container
- groups views logically
- does NOT create real layout
- does NOT add spacing
- does NOT stack views visually
Unlike:
VStack
HStack
ZStack
which create layout behaviour.
Are you thinking 🤔 Group looks similar to the @ViewBuilder
HUGE Important Insight
Group is NOT @ViewBuilder
Many developers confuse them.
@ViewBuilder
- compiler syntax transformation
- compile-time only
Group
- an actual SwiftUI type
- a real view container
Think Like This
@ViewBuilder
“How can multiple expressions become one view?”
Group
“How can I hold multiple child views without layout?”
“Hope things will be cleared and understand the intent behind the @ViewBuilder, ViewModifier and Group“
Photo by Alexas_Fotos on Unsplash
메타데이터
- post_id
- bde892da94f0
- slug
- swiftui-internals-understanding-viewbuilder-and-viewmodifier-bde892da94f0
- url
- https://medium.com/@kumarrajnees/swiftui-internals-understanding-viewbuilder-and-viewmodifier-bde892da94f0
- canonical_url
- https://medium.com/@kumarrajnees/swiftui-internals-understanding-viewbuilder-and-viewmodifier-bde892da94f0
- author_url
- https://medium.com/@kumarrajnees
- status
- ok
- fetched_at
- 2026-08-08 00:02:55