SwiftUI · · 5 min read

How To Style SwiftUI Buttons in iOS 15

How To Style SwiftUI Buttons in iOS 15

In iOS 15, Apple introduced a new way to customize buttons in iOS apps for both SwiftUI and UIKit frameworks. While this tutorial focuses on the new features of SwiftUI, you can refer to this fantastic article, written by Sarun, about how to style UIButton in iOS 15.

Styling a Button in SwiftUI

Before we dive into the new modifiers introduced in iOS 15, let’s revisit how we style a button in the current version of iOS.

swiftui-button-in-ios-15

Let’s say, we want to create a button with rounded corners, we write the code like this:

Button(action: {}) {
    Text("Buy me a coffee")
}
.padding()
.foregroundColor(.white)
.background(Color.purple)
.clipShape(RoundedRectangle(cornerRadius: 5))

We customize the button’s foreground and background color, apply paddings, and round its corners using the .clipShape modifier.

In iOS 15, to create a similar button with rounded corners, you can use a new modifier called buttonBorderShape and apply a new style called BorderedProminentButtonStyle like this:

Button(action: {}) {
    Text("Buy me a coffee")
}
.tint(.purple)
.buttonStyle(.borderedProminent)
.buttonBorderShape(.roundedRectangle(radius: 5))
.controlSize(.large)

By applying the .borderedProminent style, iOS renders the button with purple background and display the text in white. The .buttonBorderShape modifier lets you set the border shape of the button. Here, we set it to .roundedRectangle to round the button’s corners.

Control Size for Buttons

The .controlSize allows you to change the size of the button. The default size is .regular. Other valid values includes .large, .small, and .mini. The figure below shows you how the button looks for different sizes.

swiftui-buttons-control-size

Button Border Shape

Other than using .roundedRectangle, SwiftUI provides another border shape named .capsule for developers to create a capsule shape button.

swiftui-button-border-shape

You can also use the .automatic option to let the system adjust the shape of the button.

Changing the Button Style

So far, we use the .borderProminent button style. The new version of SwiftUI provides other built-in styles including .bordered, .borderless, and .plain. The .bordered style is the one you will usually use. The figure below displays a sample button using the .bordered style in both light and dark modes.

swiftui-button-style

Of course, you can create the same button using your own implementation. This new style, introduced in iOS 15, saves you time from writing your own code.

Applying Style to Multiple Buttons

With button style, you can easily apply the same style to a group of buttons. Here is an example:

VStack {
    Button(action: {}) {
        Text("Add to Cart")
            .font(.headline)
    }

    Button(action: {}) {
        Text("Discover")
            .font(.headline)
            .frame(maxWidth: 300)
    }

    Button(action: {}) {
        Text("Check out")
            .font(.headline)
    }
}
.tint(.purple)
.buttonStyle(.bordered)
.controlSize(.large)

Using Button Role

The iOS 15 version of the SwiftUI framework introduces a new role option for Button. This option describes the semantic role of the button. Based on the given role, iOS automatically renders the appropriate look & feel for the button.

For example, if you define the role as .destructive like this:

Button("Delete", role: .destructive) {
    print("Delete")
}
.buttonStyle(.borderedProminent)
.controlSize(.large)

iOS will display the delete button in red automatically. The following figure shows you the appearance of the button for different roles and button styles:

swiftui-button-role

Confirmation Dialog

Other than the new button style, iOS 15 comes with a new modifier called .confirmationDialog that you can attach to a Button for displaying a confirmation dialog.

Here is a sample code snippet for presentating the dialog:

struct DemoView: View {
    @State private var isShowingDialog = false
    var body: some View {
        Button("Delete", role: .destructive) {
            isShowingDialog = true
        }
        .buttonStyle(.borderedProminent)
        .controlSize(.large)
        .confirmationDialog("Are you sure to delete the data?", isPresented: $isShowingDialog, titleVisibility: .visible) {

            Button("Confirm", role: .destructive) {
                // Handle the delete action.
            }
            Button("Cancel", role: .cancel) {

            }
        }
    }
}

The .confirmationDialog modifier takes in a title and a binding to a Boolean value that determines whether to present the dialog. Optionally, you can indicate whether the dialog should display the title.

With the code above, the confirmation dialog will be presented like the figure below.

swiftui-confirmation-dialog

Customizing the Button with Materials

In iOS 15, SwiftUI introduces a material type for developers to create different types of blur effects. You can apply a blur effect to a view that appears behind another view by adding one of the following materials using the .background modifier:

  • .ultraThickMaterial
  • .thickMaterial
  • .regularMaterial
  • .thinMaterial
  • .ultraThinMaterial

Here is the sample code snippet which applies the .ultraThinMaterial:

Button(action: {}) {
    Text("Add to Cart")
        .font(.headline)
}
.padding()
.background(.ultraThinMaterial, in: Capsule())

As explained by Apple, adding a material is like inserting a translucent layer between the modified view and its background. Depending on the material you use, it will achieve a different blur effect. The following figure demonstrates the blur effect of different materials.

swiftui-background-material

Toggle Button

swiftui-toggle

Toggle in iOS appears in the form of switch. In iOS 15, you can configure a toggle to appear like a button by using the .toggleStyle modifier like this:

struct DemoView: View {
    @State private var isEnabled = false

    var body: some View {

        Toggle(isOn: $isEnabled) {
            Label("Airplane mode", systemImage: "airplane.circle.fill")
        }
        .padding()
        .tint(.purple)
        .controlSize(.large)
        .toggleStyle(.button)
    }
}

By setting the toggle style to .button, the toggle appears like a button. The figure below shows how it looks when the toggle is in ON/OFF state.

swiftui-toggle-button-ios-15

Summary

iOS 15 brings a number of improvements for customizing SwiftUI buttons. While you can create your own solution to style a button, the new version of SwiftUI makes developers’ job even easier with some built-in styles.

The only downside of all these new features is that you can only use them in iOS 15. If your apps require to support older versions of iOS, you will need to style the button with your own implementation.

Read next