TechnologiesSwiftUI

PrimitiveButtonStyle protocol

iOSmacOStvOSwatchOSvisionOSiOS 13.0+✓ renders

A type that applies custom interaction behavior and a custom appearance to

How it works

PrimitiveButtonStyle is the protocol you adopt to define a button's appearance and its interaction behavior from the ground up. Unlike ButtonStyle, which only restyles a button's body and leaves SwiftUI to handle press detection and triggering, a PrimitiveButtonStyle is responsible for deciding when the button fires — it receives a trigger() action and chooses which gesture or interaction invokes it. Reach for PrimitiveButtonStyle when you need full control over how a button is activated — a custom gesture, a long-press, a double-tap, or any non-standard interaction — rather than just changing how a standard tap looks.

  1. Conform a style type to PrimitiveButtonStyle

    Declare a type that adopts the protocol; SwiftUI then lets you apply it to any button. Here OutlineButtonStyle conforms to PrimitiveButtonStyle, packaging both the look and the activation rule in one reusable value.

  2. Implement makeBody(configuration:)

    The single required method returns the view that represents the button. It hands you a Configuration value describing the button, and whatever view you return becomes the button's rendered body. In the example makeBody(configuration:) returns the styled label decorated with .overlay and a RoundedRectangle stroke.

  3. Render the button's content with configuration.label

    Configuration exposes label, a type-erased view holding the title or content the call site passed to Button. You position and decorate it however you like — configuration.label here receives .font(.headline), horizontal and vertical .padding, and the bordered overlay that gives the style its outlined look.

  4. Fire the action with configuration.trigger()

    Because a primitive style owns the interaction, nothing happens until you call trigger() — the closure that runs the button's action. You wire it to whatever gesture you choose; the example attaches .onTapGesture { configuration.trigger() }, so a tap on the outlined shape invokes the button's taps += 1 action.

  5. Apply the style with .buttonStyle(_:)

    Pass an instance of your conforming type to buttonStyle(_:) on a button (or an enclosing view to style a whole subtree). In the body, Button("Tap Me") { taps += 1 }.buttonStyle(OutlineButtonStyle()) adopts the custom primitive style for that button.

Try it — Change .onTapGesture { configuration.trigger() } to .onLongPressGesture { configuration.trigger() } and watch the button fire only on a sustained press — proof that a PrimitiveButtonStyle defines the activation gesture itself.

Example & preview

Press Run live & edit to compile it in your browser — then edit the Swift on the left and the preview re-renders live.

PrimitiveButtonStyle.swift
struct PrimitiveButtonStyleDemo: View {
    struct OutlineButtonStyle: PrimitiveButtonStyle {
        func makeBody(configuration: Configuration) -> some View {
            configuration.label
                .font(.headline)
                .padding(.horizontal, 20)
                .padding(.vertical, 10)
                .overlay(
                    RoundedRectangle(cornerRadius: 10)
                        .stroke(Color.blue, lineWidth: 2)
                )
                .onTapGesture { configuration.trigger() }
        }
    }

    @State private var taps = 0

    var body: some View {
        VStack(spacing: 16) {
            Text("Tapped \(taps) times")
            Button("Tap Me") { taps += 1 }
                .buttonStyle(OutlineButtonStyle())
        }
        .padding()
    }
}
Live preview
Tapped 0 times Tap Me
Tapped 0 times Tap Me
swift → lexer → parser → sema → uiir → canvas Open in Studio ↗
What's new in SwiftUI 27 →