@ViewBuilder in SwiftUI is a powerful attribute that allows you to create custom views with conditional or multiple child views. With @ViewBuilder, you can define functions or properties that return different views or combinations of views based on conditions, without needing to wrap them in AnyView. It’s widely used in SwiftUI and can be applied to function parameters, making it flexible for dynamic view construction.
Basic Usage of @ViewBuilder
When creating functions that return multiple or conditional views, you typically use @ViewBuilder to handle the variations. Let’s look at a simple example where a function returns different views based on a condition.
import SwiftUI
struct ContentView: View {
var body: some View {
VStack {
greetingMessage(isMorning: true)
greetingMessage(isMorning: false)
}
}
@ViewBuilder
func greetingMessage(isMorning: Bool) -> some View {
if isMorning {
Text("Good Morning!")
} else {
Text("Good Evening!")
}
}
}
In this example:
@ViewBuilderallowsgreetingMessage(isMorning:)to return eitherText("Good Morning!")orText("Good Evening!")without additional type wrapping.- The function returns
some Viewwithout needingAnyView, even though the returned views vary based on the condition.
Using @ViewBuilder with Multiple Views
You can also use @ViewBuilder to return multiple views, allowing for flexible composition within a single function.
import SwiftUI
struct ContentView: View {
var body: some View {
VStack {
profileHeader()
}
}
@ViewBuilder
func profileHeader() -> some View {
Text("User Name")
.font(.title)
Image(systemName: "person.circle")
.resizable()
.frame(width: 50, height: 50)
}
}

Here, profileHeader() returns a Text and an Image without needing any container view (like a VStack), thanks to @ViewBuilder.
Example with Conditional Views
@ViewBuilder is particularly useful in complex conditional statements, where multiple conditions need to return different views.
import SwiftUI
struct ContentView: View {
@State private var isLoggedIn = true
@State private var isAdmin = false
var body: some View {
VStack {
roleView()
.padding()
Button("Toggle Admin Role") {
isAdmin.toggle()
}
Button("Toggle Login Status") {
isLoggedIn.toggle()
}
}
}
@ViewBuilder
func roleView() -> some View {
if isLoggedIn {
if isAdmin {
Text("Welcome, Admin!")
} else {
Text("Welcome, User!")
}
} else {
Text("Please Log In")
}
}
}

In this example:
- Nested Conditionals:
roleView()adjusts its return view based onisLoggedInandisAdminwithout needingAnyView. - Dynamic Layout: By managing various user roles and states, it shows different views accordingly.
@ViewBuilder in Custom View Initializers
You can use @ViewBuilder in custom view initializers to allow flexible child views. This is commonly seen in SwiftUI’s built-in components like VStack and HStack.
import SwiftUI
struct CardView<Content: View>: View {
let title: String
let content: Content
init(title: String, @ViewBuilder content: () -> Content) {
self.title = title
self.content = content()
}
var body: some View {
VStack {
Text(title)
.font(.headline)
content
}
.padding()
.background(Color.gray.opacity(0.2))
.cornerRadius(10)
}
}
struct ContentView: View {
var body: some View {
CardView(title: "Important Notice") {
Text("Your account has been updated successfully.")
Image(systemName: "checkmark.circle.fill")
.foregroundColor(.green)
}
}
}

In this example:
CardViewis a reusable custom component that takes atitleand a@ViewBuilder content.- The
@ViewBuilderallows multiple views to be passed directly, makingCardViewa flexible container for any content.
Summary of @ViewBuilder
- Multiple View Return Types: Enables functions to return different views or combinations without
AnyView. - Improved Type Safety: Eliminates the need for type erasure, which reduces performance overhead and enhances Swift’s type safety.
- Custom Containers: Allows you to create components that accept multiple child views, just like
VStackorHStack. - Dynamic Layouts: Useful for creating views with complex conditional logic.
Limitations of @ViewBuilder
- Limited Logic:
@ViewBuildercan only return up to ten views in one scope (although nested views help extend this). - No Variable Storage: You can’t store values directly inside
@ViewBuildercode. You need separate@State,@Binding, or calculated properties to manage states.
By using @ViewBuilder, you can enhance the flexibility and readability of your SwiftUI code, making it easier to create dynamic, reusable views that handle a variety of layouts and conditions!