A brief introduction
Everything is a View in SwiftUI. This was made clear from the very first SwiftUI talk at WWDC 2019. This concept is core to how SwiftUI works - and if you really think about it - it makes perfect sense. SwiftUI Views don't maintain state, they're redrawn with every layout pass, the old ones are discarded and new ones take their place. Modifying a View in a literal sense wouldn't work as we have no reference to it. In the case of SwiftUI a view modifier actually refers to creating a new view from the state of the old one.
Let's take a quick look at an example.
import SwiftUI
import PlaygroundSupport
struct CustomRectangleView: View {
var body: some View {
RoundedRectangle(cornerRadius: 15)
}
}
PlaygroundPage.current.setLiveView(CustomRectangleView())
This code creates a SwiftUI View inside a playground, right now it's just a rectangle with a corner radius, that's it. SwiftUI will make the rounded rectangle just big enough to accommodate the corner radius and give it a default fill of black. It results in the following.

Now let's add a couple of view modifiers...
import SwiftUI
import PlaygroundSupport
struct CustomRectangleView: View {
var body: some View {
RoundedRectangle(cornerRadius: 7)
.fill(
LinearGradient(gradient:
Gradient(colors: [.blue, .green]),
startPoint: .top,
endPoint: .bottom)
)
.frame(width: 140, height: 200)
}
}
PlaygroundPage.current.setLiveView(CustomRectangleView())
The above code adds two modifiers, fill
and frame
.
fill
takes in any View and uses it to fill the contents of the RoundedRectangleframe
sets the size - or frame - of the View.
It results in the following.

Looks much cooler right? So far you've looked at some built in View modifiers SwiftUI provides, but that's not why you're here. How do you go about creating your own?
Adding your own modifiers
Adding your own modifiers is much easier than it sounds. It involves two steps:
- Create a
struct
and subscribe to theViewModifier
protocol - Override
body(content:) -> some View
Let's see how this looks in practice.
struct CustomTextField: ViewModifier {
func body(content: Content) -> some View {
content
.frame(minWidth: 0, maxWidth: .infinity)
.frame(height: 43)
.padding(.horizontal)
.font(.system(size: 18, weight: .medium, design: .rounded))
.foregroundColor(Color(UIColor.label))
.background(
RoundedRectangle(cornerRadius: 10)
.foregroundColor(
Color(UIColor.quaternarySystemFill)
)
)
}
}
In this example we're combing multiple view mofidiers into one inside the body(content:) -> some View
function. content
in this case is the View
you're adding the modifier to.
To apply the CustomTextField
modifier, you pass it as an argument to the .modifier
view modifier. Take a look at the following example.
TextField("Email", text: $email)
.modifier(CustomTextField())
That's it! You can combine any number of view modifiers into custom ones, you can even combine multiple custom ones, totally your call 😄.
Using this view modifier, a login form would look something like this.

Thanks for reading ✌️