iOS 26 Liquid Glass Gotcha: Adjacent Buttons Silently Swallowing Taps

Published: (May 1, 2026 at 03:25 PM EDT)
3 min read
Source: Dev.to

Source: Dev.to

The Setup

Two buttons stacked vertically, 26 pt apart, using a standard VStack layout:

VStack(spacing: 26) {
    Spacer()

    Button {
        store.send(.signupButtonTapped)
    } label: {
        Text("Sign Up")
            .padding()
            .frame(width: buttonWidth, height: 55)
    }
    .glassEffect(.clear.interactive())
    .buttonStyle(.plain)

    Button {
        store.send(.loginButtonTapped)
    } label: {
        Text("Log In")
            .padding()
            .frame(width: buttonWidth, height: 50)
    }
    .glassEffect(.clear.interactive())
    .buttonStyle(.plain)
}

App's Screenshot

Sign Up works; Log In does nothing. The code and modifiers are identical—the only difference is their position.

The Cause

Calling .glassEffect(.clear.interactive()) without specifying a shape defaults the glass platter to a rectangle. In iOS 26, the Liquid Glass system automatically merges adjacent glass surfaces that are close together into a single interactive group.

When merged, the .interactive() gesture handler routes taps to the first view in the hierarchy—the Sign Up button in this case. The Log In button’s taps are silently consumed by the merged glass group and never reach its action.

The merging behavior is intentional (Apple wants glass elements to feel like one fluid surface), but the side‑effect on gesture routing makes debugging extremely difficult because there’s no visible error.

The Fix

Specify an explicit shape with the in: parameter:

// Before (broken)
.glassEffect(.clear.interactive())

// After (works)
.glassEffect(.clear.interactive(), in: .capsule)

Giving each button a distinct glass shape prevents the automatic merge, so each button receives its own gesture handler.

A Reusable Modifier

If you wrap glass effects in a ViewModifier for backward compatibility, be sure to include the shape:

struct GlassButtonModifier: ViewModifier {
    func body(content: Content) -> some View {
        if #available(iOS 26.0, *) {
            content.glassEffect(.clear.interactive(), in: .capsule)
        } else {
            content
                .background(.ultraThinMaterial, in: Capsule())
        }
    }
}

When to Watch Out

This issue will bite you whenever:

  • Two or more .glassEffect() views are adjacent (e.g., in a VStack, HStack, or ZStack).
  • You’re using .interactive() for press/bounce feedback.
  • You haven’t specified a shape with in:.

It’s especially dangerous because the first button always works, so the problem may go unnoticed until a user reports a dead button.

TL;DR

VariantShape (default)Merge?Tap behavior
.glassEffect(.clear.interactive())rectangleYesOnly first button receives taps
.glassEffect(.clear.interactive(), in: .capsule)capsuleNoAll buttons receive taps

Always pass a shape to .glassEffect() when using .interactive() on adjacent views. Future you will thank present you.

Sources

0 views
Back to Blog

Related posts

Read more »