Button or onTapGesture grows its hit region by a fixed amount past the view’s bounds.

SwiftUI Button hit area extends ~16pt beyond its visual frame — expected OS behavior?

Hi everyone,

I’m working on a custom SwiftUI segmented control and noticed some unexpected hit-testing behavior with Button.

I have a button structured roughly like this:

Button {
    selectItem(at: index)
} label: {
    ZStack {
        if selectedIndex == index {
            selectedBackground
        }

        SegmentCellView(
            tab: tab,
            isSelected: selectedIndex == index
        )
    }
    .frame(maxWidth: .infinity)
    .contentShape(Rectangle())
}
.accessibilityLabel(Text(tab.labelText))

The visual frame of the button has a certain height, but when testing on a real device, I can tap approximately 16pt outside the button's visible frame and the button still receives the tap.

This seems to happen even though I explicitly use:

.contentShape(Rectangle())

to define the tappable shape.

My questions are:

  1. Is this ~16pt expansion of the interactive area expected SwiftUI/OS behavior?
  2. Is this related to Apple's minimum hit-target/accessibility guidelines being automatically applied to controls such as Button?
  3. If so, is there an official API/documentation describing this behavior?
  4. Is there a recommended way to make the Button's hit-testing area exactly match the bounds defined by .contentShape(Rectangle()), if that is actually possible?

I'm particularly interested in understanding whether this is intentional system behavior or something caused by the ButtonStyle / layout hierarchy.

Thanks!

Button or onTapGesture grows its hit region by a fixed amount past the view’s bounds.
 
 
Q