Liquid Glass buttons that worked in the simulator and did nothing on my iPhone

3 min read

SwiftUIiOS 26Liquid Glass

Every close, share and camera button in Backmark fired in the simulator and ignored my finger on a real phone. Two small modifiers were to blame.

Backmark was built and tested on the simulator for days. Every screen worked. Then I installed it on my iPhone, and many of the buttons did nothing. The close button on the scan screen, Share on the result, the photo button on the camera, Use Photo, Cancel during the examination: I tapped, and nothing happened.

They all had one thing in common. They were small floating controls on Liquid Glass, the material iOS 26 uses for controls that sit over content.

The button that ate its own tap

Each of them was written the same way:

Button(action: close) {
    Image(systemName: "xmark")
        .frame(width: 44, height: 44)
}
.buttonStyle(.plain)
.glassEffect(.regular.interactive(), in: Circle())

.interactive() asks the glass to react to touch: it responds when you press it, the way system controls do. It sounds like exactly what a button wants. On the device it was the problem. The interactive glass took the touch for itself, and the button underneath never received it.

The fix was to keep the glass and drop the word:

.glassEffect(.regular, in: Circle())

Every one of those buttons worked on the next install. You give up the glass's own press response, and for small round controls like these I didn't miss it.

Why the simulator didn't show it

In the simulator you click with a mouse. A click is not a finger: it has no size, no pressure and no movement, and in my case it went straight through to the button every time. Nothing in days of testing hinted at a problem.

This is the lesson I took from it more than the fix itself. Anything to do with touch, gestures or controls drawn over content needs a real device early, not in the last week before submission.

The second problem: a circle that only listened to its icon

A few days later I noticed something smaller. The share button and a couple of close buttons now fired, but only sometimes. Tapping the middle of the icon worked. Tapping the edge of the glass circle, which is where a thumb often lands, did nothing.

With .buttonStyle(.plain), the button only answered on the drawn pixels of the symbol. The glass circle around it looked like part of the button, but it wasn't part of the tappable area. A thin share arrow leaves most of a 44 point circle empty.

One modifier on the label fixes it:

Button(action: share) {
    Image(systemName: "square.and.arrow.up")
        .frame(width: 44, height: 44)
        // The whole circle takes the tap, not only the glyph's pixels.
        .contentShape(Circle())
}
.buttonStyle(.plain)
.glassEffect(.regular, in: Circle())

contentShape tells SwiftUI which area counts as the button. Give it the same shape as the glass, and what the person sees is exactly what they can tap.

What I check now

  • No .interactive() on glass that wraps a button. If a control needs to respond to touch, the button does that job.
  • A contentShape on every icon button. It should match the visible shape, and be at least 44 by 44 points, the minimum Apple's guidelines ask for.
  • Every new control tried on a real iPhone, with a thumb, on the same day it is written.

None of this was hard to fix. It was hard to notice, because the tool I tested with couldn't make the mistake a finger makes. If your Liquid Glass buttons work in the simulator and not on a phone, start with those two modifiers.