Button border, tint, and role in SwiftUI 3 and iOS 15

Several new additions have been made to button control under SwiftUI 3 and iOS 15 release and in this article, we will be looking at four major changes that will make buttons look better out of the box.

BorderShape:

Button’s border can be created by adding a background modifier to the button but in iOS 15 there is another way to create border. BorderShape is a new modifier added in iOS 15 to add border to Button controls in SwiftUI.

struct ButtonBorderExample: View {
var body: some View {
VStack {
Button("Just bordered no shape") {}
.buttonStyle(.bordered)

Button("Just borderedProminent no shape") {}
.buttonStyle(.borderedProminent)

Button("borderedProminent and automatic shape") {}
.buttonStyle(.borderedProminent)
.buttonBorderShape(.automatic)

Button("borderedProminent and roundedRectangle shape") {}
.buttonStyle(.borderedProminent)
.buttonBorderShape(.roundedRectangle)

Button("borderedProminent and roundedRectangle(20)") {}
.buttonStyle(.borderedProminent)
.buttonBorderShape(.roundedRectangle(radius: 20))

Button("borderedProminent and capsule") {}
.buttonStyle(.borderedProminent)
.buttonBorderShape(.capsule)
}
}
}

SwiftUI team has added four options to choose from in order to specify the border shape. This modifier can only be applied to bordered buttons so following will not add borderShape on button:

Button("borderless and capsule") {}
.buttonStyle(.borderless)
.buttonBorderShape(.capsule)

ControlSize

ControlSize is another modifier that was introduced and works well with buttons. ControlSize adds padding around content of the button. ControlSize comes with four values mini, small, regular and large. Amount of padding is determined by the system.

struct ButtonControlSizeExample: View {
var body: some View {
VStack {

Button("Mini") {}
.buttonStyle(.borderedProminent)
.buttonBorderShape(.roundedRectangle)
.controlSize(.mini)

Button("Small") {}
.buttonStyle(.borderedProminent)
.buttonBorderShape(.roundedRectangle)
.controlSize(.small)

Button("Regular") {}
.buttonStyle(.borderedProminent)
.buttonBorderShape(.roundedRectangle)
.controlSize(.regular)

Button("Large") {}
.buttonStyle(.borderedProminent)
.buttonBorderShape(.roundedRectangle)
.controlSize(.large)

}
}
}

Tint

Starting iOS 15, accentColor modifier has been marked for deprecation in future iOS releases. tint modifier is the replacement for accentColor .

struct ButtonBorderExample: View {
var body: some View {
VStack {
Button("bordered") {}
.buttonStyle(.bordered)
.controlSize(.large)
.buttonBorderShape(.capsule)

Button("borderless") {}
.buttonStyle(.borderless)
.controlSize(.large)
.buttonBorderShape(.capsule)

Button("borderedProminent") {}
.buttonStyle(.borderedProminent)
.controlSize(.large)
.buttonBorderShape(.capsule)

Button("automatic") {}
.buttonStyle(.automatic)
.controlSize(.large)
.buttonBorderShape(.capsule)

Button("plain") {}
.buttonStyle(.plain)
.controlSize(.large)
.buttonBorderShape(.capsule)

}.tint(Color.orange)
}
}

tint and accentColor work pretty much same except one use case. In order to understand this better, let’s put tint and accentColor side by side

Role:

role is an optional parameter and can be used to specify semantic role for the Button. Role also determines the appearance of button as we can see below:

struct ButtonBorderExample: View {
var body: some View {
VStack {
Text("Button Role")
.font(.largeTitle)

Button("destructive", role: .destructive) {}
.buttonStyle(.bordered)
.controlSize(.large)
.buttonBorderShape(.capsule)

Button("cancel", role: .cancel) {}
.buttonStyle(.borderless)
.controlSize(.large)
.buttonBorderShape(.capsule)

Button("none", role: .none) {}
.buttonStyle(.borderedProminent)
.controlSize(.large)
.buttonBorderShape(.capsule)

Button("destructive w/ borderedProminent", role: .destructive) {}
.buttonStyle(.borderedProminent)
.controlSize(.large)
.buttonBorderShape(.capsule)

Button("no role") {}
.buttonStyle(.plain)
.controlSize(.large)
.buttonBorderShape(.capsule)

}
}
}

Applying tint will override style applied by role

struct ButtonBorderExample: View {
var body: some View {
VStack {
Text("Button Role")
.font(.largeTitle)

Button("destructive", role: .destructive) {}
.buttonStyle(.bordered)
.controlSize(.large)
.buttonBorderShape(.capsule)

Button("cancel", role: .cancel) {}
.buttonStyle(.borderless)
.controlSize(.large)
.buttonBorderShape(.capsule)

Button("none", role: .none) {}
.buttonStyle(.borderedProminent)
.controlSize(.large)
.buttonBorderShape(.capsule)

Button("destructive w/ borderedProminent", role: .destructive) {}
.buttonStyle(.borderedProminent)
.controlSize(.large)
.buttonBorderShape(.capsule)

Button("no role") {}
.buttonStyle(.plain)
.controlSize(.large)
.buttonBorderShape(.capsule)

}.tint(.orange)
}
}

With that, we have reached the end of this article. Thank you once again for reading, if you liked it, don’t forget to 👏 and follow 😍.

Your support makes big difference. It allows us to focus time and resources to write for this blog so please consider supporting us at: https://www.patreon.com/DevTechieInc

Thank you!

DT