How to Better Use ButtonStyle in SwiftUI

Sergey Chsherbak
3 min readFeb 7, 2023

--

The image shows the topic of the article and the name of the author. The author’s name is Chsherbak Sergey

SwiftUI provides a powerful way to create and customise views using styling protocols. These protocols allow us to define the look and feel of our views in a single line of code.

As a result, the views are visually consistent, making the app easier to use and more attractive.

Styling Button without ButtonStyle

We could style our button inline by applying different modifiers to it. Consider this example:

Button("Tap me") {}
.font(.system(.callout, weight: .bold))
.foregroundColor(.white)
.frame(maxWidth: .infinity, maxHeight: 48)
.background(.blue)
.cornerRadius(8)

This will yield the following result:

Button in the normal state

This approach is completely fine if you design a single button. But if you need to develop multiple buttons with the same style you need to use the ButtonStyle protocol. It will help share and apply the same style to different buttons across the app.

Styling Button with ButtonStyle

Let’s create our custom button style named PrimaryButtonStyle. This is the style used for primary buttons throughout the application.

Let’s take a look at this example:

struct PrimaryButtonStyle: ButtonStyle {

func makeBody(configuration: Configuration) -> some View {
configuration.label
.font(.system(.callout, weight: .bold))
.foregroundColor(.white)
.frame(maxWidth: .infinity, maxHeight: 48)
.background(.blue)
.cornerRadius(8)
}
}

To create a custom button style, we need to confirm to ButtonStyle protocol and implement the makeBody(configuration:) method. This method returns the body of the button, which is typically a view that can be positioned and styled to match the desired appearance.

To apply the created button style try writing this:

Button("Tap me") {}
.buttonStyle(PrimaryButtonStyle())

It is now possible to apply the PrimaryButtonStyle to any button within your application, thus allowing you to create consistent and reusable buttons throughout your entire application.

ButtonStyleConfiguration

The button’s configuration object has several properties, including the isPressed boolean value, which indicates whether or not the button is currently being pressed. We could use that to change our button style when a user taps a button. To do that, we could write something like this:

struct PrimaryButtonStyle: ButtonStyle {

func makeBody(configuration: Configuration) -> some View {
configuration.label
.font(.system(.callout, weight: .bold))
.foregroundColor(.white)
.frame(maxWidth: .infinity, maxHeight: 48)
.background(configuration.isPressed ? .blue.opacity(0.75) : .blue)
.cornerRadius(8)
}
}

Now the button looks different in the normal or highlighted states:

Button in the normal and highlighted states

Pro tip

Our code can be made cleaner and more readable by adding the following extension to the PrimaryButtonStyle:

extension ButtonStyle where Self == PrimaryButtonStyle {

static var primary: PrimaryButtonStyle {
PrimaryButtonStyle()
}
}

Now we can apply our button style as easily as this:

Button("Tap me") {}
.buttonStyle(.primary)

Conclusion

With ButtonStyle, we can define the appearance, layout, and interactions of a button and ensure consistency across the entire application.

In addition, it provides a way to encapsulate button-related logic and styling into reusable components. This makes the codebase more maintainable and scalable.

Thanks for reading!

If you find this article helpful, be sure to give it a clap so others can discover it more easily.

--

--

Sergey Chsherbak
Sergey Chsherbak

Written by Sergey Chsherbak

iOS Engineer based in Copenhagen. Writing about Swift for fun. Working with Swift for food.

No responses yet