Faking Apple's frosted-glass chrome before iOS 26 meant stacking .ultraThinMaterial behind a shape and hand-tuning opacity and a stroke overlay until it roughly matched system controls — it never actually refracted or reacted to the content behind it the way native glass does.
#The old way
Text("42")
.font(.headline)
.padding()
.background(.ultraThinMaterial, in: Circle())
.overlay(Circle().strokeBorder(.white.opacity(0.2)))
#The new way
struct AdaptiveBadge: View {
let count: Int
var body: some View {
let label = Text("\(count)")
.font(.headline)
.foregroundStyle(.primary)
.padding()
if #available(iOS 26, *) {
label.glassEffect(.regular.tint(.blue).interactive(), in: .circle)
} else {
label.background(.ultraThinMaterial, in: Circle())
}
}
}
#Why it matters
- Real-time refraction and specular highlights sampled from the content behind the view, not a flat blur
.tint(_:)and.interactive()chain onto.regularor.prominentwithout extra modifiers- Automatically tracks system chrome as Apple continues to tune the material across OS updates
#Gotcha
.glassEffect() has to come after your layout and appearance modifiers — padding, font, background color — not before. Apply it first and you glass an unstyled, unpadded view, with everything that follows composited on top of the glass instead of inside it. It's also new API: check GlassEffectStyle's exact case list and defaults against current docs before relying on anything beyond .regular, .prominent, .tint(_:), and .interactive().