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.
Conform a style type to
PrimitiveButtonStyleDeclare a type that adopts the protocol; SwiftUI then lets you apply it to any button. Here
OutlineButtonStyleconforms toPrimitiveButtonStyle, packaging both the look and the activation rule in one reusable value.Implement
makeBody(configuration:)The single required method returns the view that represents the button. It hands you a
Configurationvalue describing the button, and whatever view you return becomes the button's rendered body. In the examplemakeBody(configuration:)returns the styled label decorated with.overlayand aRoundedRectanglestroke.Render the button's content with
configuration.labelConfigurationexposeslabel, a type-erased view holding the title or content the call site passed toButton. You position and decorate it however you like —configuration.labelhere receives.font(.headline), horizontal and vertical.padding, and the bordered overlay that gives the style its outlined look.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'staps += 1action.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.
.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.
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()
}
}