Apple shipped the Liquid Glass design language with iOS 26, and SwiftUI exposes most of it through a single new modifier: .glassEffect(_:in:). The API surface is tiny. The behavior is not. This is the condensed version of what I learned wiring it into a production app.
iOS 26 Liquid Glass in SwiftUI: the modifiers, the gotchas, the fallbacks
Apple shipped the Liquid Glass design language with iOS 26, and SwiftUI exposes most of it through a single new modifier: .glassEffect(_:in:). The API surface is tiny. The behavior is not.

import SwiftUI
struct FloatingToolbar: View {
var body: some View {
HStack(spacing: 16) {
Button(action: {}) { Image(systemName: "square.and.arrow.up") }
Button(action: {}) { Image(systemName: "heart") }
Button(action: {}) { Image(systemName: "bookmark") }
}
.padding(.horizontal, 20)
.padding(.vertical, 12)
.glassEffect(.regular, in: .capsule)
}
}That's it for the happy path. You get the refraction, the specular highlight that tracks device orientation, and the subtle inner shadow Apple uses on the system toolbars.
The four variants
.glassEffect(.regular, in: .capsule)
.glassEffect(.regular.tint(.blue), in: .capsule)
.glassEffect(.regular.interactive(), in: .capsule)
.glassEffect(.clear, in: .rect(cornerRadius: 16)).clear skips the frosting and gives you pure refraction — looks great over photography, illegible over text. .interactive() enables the live warp that follows touch input; it's gated to A17 Pro and later, and silently degrades to a static glass on older devices with no log message.
Merging multiple surfaces
If you put two .glassEffect views near each other, by default they each render their own backdrop sample and you get a visible seam. GlassEffectContainer fixes this by sharing one sample across children:
GlassEffectContainer(spacing: 12) {
HStack {
Image(systemName: "play.fill").glassEffect()
Image(systemName: "pause.fill").glassEffect()
Image(systemName: "forward.fill").glassEffect()
}
}This also unlocks the morph animation when you toggle one of the children's visibility — Apple's media controls use this pattern.
The gotchas that cost me hours
1. .clipped() kills the effect. Any ancestor that applies .clipped() or .mask() prevents the renderer from sampling the backdrop. The view falls back to a flat material with no warning. If your glass surface needs to escape a scroll container, hoist it out and use .overlay or .containerRelativeFrame to position it.
2. Form overrides glass. Form forces its own grouped material on row backgrounds. .glassEffect inside a Form row is a no-op. Use List if you need the effect on rows.
3. GlassEffectContainer does not cross NavigationStack. Matched geometry effects across navigation boundaries fall back to a fade. If you need the morph between screens, do the transition with .navigationTransition(.zoom(...)) instead.
4. Dark mode tint blending. .regular.tint(color) blends the tint at ~30% in light mode and ~50% in dark mode. If your brand color is already dark, the dark-mode result will look almost opaque. Test both.
5. Snapshot tests break. XCUITest screenshots of glass surfaces are nondeterministic because the specular highlight depends on the simulated device pose. Either snapshot a child view excluding the glass, or pin the device orientation in your test setup.
Performance notes
The interactive variant adds one extra fullscreen sample per frame. On an iPhone 15 Pro Max running a list of 12 visible glass cells, I measured the Render Server going from a stable 60 fps to dropping frames during scroll. Switching to the non-interactive variant and using one GlassEffectContainer per visible group fixed it. Rule of thumb: use .interactive() for surfaces the user is directly touching, not for ambient decoration.
When NOT to use it
Liquid Glass over dense text is a legibility disaster. The HIG calls this out gently; in practice, anything denser than a one-line label needs a solid backdrop. Apple's own Mail app uses solid surfaces for the message body and reserves glass for the toolbar.
The full version of this article on swiftcrafted.dev has the sample Xcode 26 project, Instruments traces for the fps drop, and a comparison table of the chip-tier fallbacks: https://swiftcrafted.dev/article/ios-26-liquid-glass-swiftui-tutorial


