Custom View Modifiers & ViewBuilder
As your app grows you'll repeat the same styling and structure. SwiftUI lets you package reusable styles in a ViewModifier , expose them cleanly with View extensions, accept flexible content with @ViewBuilder , and extract repeated UI into reusable views. This is how you keep a large codebase DRY.
Learn Custom View Modifiers & ViewBuilder in our free Swift course — a beginner-friendly interactive lesson with worked examples, a practice exercise and a…
Part of the free Swift course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
Building iOS Apps with SwiftUI • Intermediate
What You'll Learn in This Lesson
1️⃣ Custom ViewModifier
Conform a type to ViewModifier and implement body(content:) . The content parameter is the view you're modifying; return it wrapped with your changes. Apply it with .modifier(...) to reuse a consistent style everywhere.
2️⃣ A Clean API with a View Extension
Calling .modifier(CardStyle()) works but reads awkwardly. Add an extension on View with a convenience method so you can write .cardStyle() — exactly like a built-in modifier.
3️⃣ @ViewBuilder — Accepting Multiple Children
@ViewBuilder lets a closure return several views (and use if / switch ). It's why a VStack 's trailing closure can hold many children. Mark your own content closures with it to build flexible container views.
4️⃣ Extracting Reusable Views
When you repeat a chunk of UI, pull it into its own View struct that takes parameters. This keeps your code DRY, your body readable, and your styling consistent — and it pairs naturally with custom modifiers.
Your turn. Fill in the blanks to build a reusable pill style and expose it as .pillStyle() .
Create a TitledBox view that takes a title string and a @ViewBuilder content closure, showing the title above whatever views the caller passes. Then write a ViewModifier called RoundedBordered and expose it as .roundedBordered() . Use both together to build a tidy settings panel.
Practice quiz
What is a custom ViewModifier?
- A new View
- A reusable type that packages a set of modifications applied to a view
- A property wrapper
- A navigation link
Answer: A reusable type that packages a set of modifications applied to a view. A ViewModifier bundles modifications so you can reuse a consistent style across many views.
What method must a ViewModifier implement?
- body(content:)
- render()
- draw()
- init()
Answer: body(content:). A ViewModifier implements body(content:), returning the modified content.
What is the 'content' parameter in body(content:)?
- A string
- The view the modifier is applied to
- A color
- The parent view
Answer: The view the modifier is applied to. content is the view being modified; you return it wrapped with your changes.
How do you apply a custom ViewModifier to a view?
- view.apply(MyModifier())
- MyModifier(view)
- view.modifier(MyModifier())
- view + MyModifier()
Answer: view.modifier(MyModifier()). Call .modifier(MyModifier()) to apply a custom ViewModifier to any view.
What is a common way to make a modifier nicer to call?
- Add a View extension method that calls .modifier(...)
- Subclass View
- Use a global function only
- It cannot be improved
Answer: Add a View extension method that calls .modifier(...). An extension on View exposing a convenience method (e.g. .cardStyle()) reads cleanly.
What does @ViewBuilder do?
- Builds the app
- Compiles code
- Stores state
- Lets a closure return multiple child views (and use if/switch)
Answer: Lets a closure return multiple child views (and use if/switch). @ViewBuilder enables a closure to combine several views and use conditionals to build content.
Why can a VStack's trailing closure contain several views?
- Because of @ViewBuilder on its content parameter
- Because of @State
- Because of @Binding
- By accident
Answer: Because of @ViewBuilder on its content parameter. Container initializers mark their content closure @ViewBuilder, allowing multiple child views.
What is a clean way to reuse a chunk of UI?
- Copy and paste it
- Extract it into its own View struct (or a computed property)
- Use a global variable
- Inline everything
Answer: Extract it into its own View struct (or a computed property). Extracting repeated UI into a dedicated View struct keeps code DRY and readable.
Custom modifiers are most useful when you want to...
- Apply the same group of styling repeatedly and consistently
- Avoid using SwiftUI
- Replace the View protocol
- Disable previews
Answer: Apply the same group of styling repeatedly and consistently. They centralize a reusable style so it stays consistent and easy to change in one place.
A function or property marked @ViewBuilder can return what?
- Only one view, ever
- Several views combined into one result, with conditionals allowed
- Only strings
- Only numbers
Answer: Several views combined into one result, with conditionals allowed. @ViewBuilder composes the returned views into a single result and supports if/switch branches.