Adjust SwiftUI controls for the Button Shapes accessibility setting

Some iPhone users prefer to see clear edges and borders of buttons, so that they stand out more among regular labels in the UI. They can enable the "Button Shapes" toggle in the Accessibility settings on their device, so that the system can change the appearance of controls to suit the user's needs.

Screenshot of iPhone Display and Text accessibility settings with the Button Shapes toggle enabled Screenshot of iPhone Display and Text accessibility settings with the Button Shapes toggle enabled

In many cases SwiftUI automatically adjusts the appearance of our controls to match the user settings, for example, when we use Button views with built-in styles or framework provided NavigationLink and Link controls.

A button in SwiftUI with an automatic style will get resolved into a bordered one on devices where the "Button Shapes" setting is enabled.

Button("Open settings") {
    // open settings
}
.buttonStyle(.automatic)
Button with resolved borderless style when the Button Shapes setting is disabled and bordered style when the setting in enabled Button with resolved borderless style when the Button Shapes setting is disabled and bordered style when the setting in enabled

But sometimes we need to adjust the appearance of our controls manually to respond to the accessibility setting. This can be necessary when we are defining custom button styles or embed links inside Text views. To know whether "Button Shapes" setting is enabled, we can read the accessibilityShowButtonShapes environment value.

struct ContentView: View {
    @Environment(\.accessibilityShowButtonShapes)
    private var accessibilityShowButtonShapes

    var body: some View {
        ...
    }
}
Integrating SwiftUI into UIKit Apps by Natalia Panferova book coverIntegrating SwiftUI into UIKit Apps by Natalia Panferova book cover

Check out our book!

Integrating SwiftUI into UIKit Apps

Integrating SwiftUI intoUIKit Apps

UPDATED FOR iOS 17!

A detailed guide on gradually adopting SwiftUI in UIKit projects.

  • Discover various ways to add SwiftUI views to existing UIKit projects
  • Use Xcode previews when designing and building UI
  • Update your UIKit apps with new features such as Swift Charts and Lock Screen widgets
  • Migrate larger parts of your apps to SwiftUI while reusing views and controllers built in UIKit

# Adjust custom button styles

When creating custom button styles that don't give a stand-out shape to the button, we should consider adding a background, a border or an underline to the button when accessibilityShowButtonShapes is set to true.

struct ScalingButtonStyle: ButtonStyle {
    @Environment(\.accessibilityShowButtonShapes)
    private var accessibilityShowButtonShapes
    
    func makeBody(configuration: Configuration) -> some View {
        configuration.label
            .foregroundColor(.blue)
            .padding()
            .border(
                .blue,
                width: accessibilityShowButtonShapes ? 1 : 0
            )
            .scaleEffect(configuration.isPressed ? 1.5 : 1)
            .animation(.default, value: configuration.isPressed)
    }
}

Standalone Link views and NavigationLinks get automatically adjusted to respond to the "Button Shapes" setting. But links embedded inside Text views using Markdown or AttributedString don't change their appearance.

VStack(spacing: 60) {
    Link(
        "Visit our website",
        destination: URL(
            string: "https://example.com"
        )!
    )
    
    Text("""
    [Visit our website](https://example.com) \
    to learn more about our products.
    """)
}
.multilineTextAlignment(.center)
A Link view with a bordered button style when the Button Shapes setting is enabled and a Text view with a link inside that is simply tinted in blue A Link view with a bordered button style when the Button Shapes setting is enabled and a Text view with a link inside that is simply tinted in blue

We can make the link inside text more prominent by adding an underline when the accessibilityShowButtonShapes is set to true. We can do that by wrapping it in a separate Text view and make use of the LocalizedStringKey.StringInterpolation.

struct ContentView: View {
    @Environment(\.accessibilityShowButtonShapes)
    private var accessibilityShowButtonShapes
    
    var body: some View {
        Text("""
        \(
            Text("[Visit our website](https://example.com)")
                .underline(accessibilityShowButtonShapes)
        ) to learn more about our products.
        """)
        .multilineTextAlignment(.center)
    }
}