Overview
Updated · 20 May 2026 · This is a living reference. Originally published 16 Nov 2025 against iOS 26.0. Refreshed in May 2026 with a second research pass covering iOS 26.1–26.4 point releases (Tinted mode, Lock Screen Glass/Solid, Reduce Bright Effects), expanded sheet-morph guidance, the UIKit+SwiftUI hybrid recipe, a Web & Cross-Platform appendix, a Community Reception section, and forward-looking notes on WWDC 2026 (8 June 2026). See Part 7: Point-Release Changelog for the full diff.
iOS 26 Liquid Glass represents Apple's most significant design evolution since iOS 7, introduced at WWDC 2025 (June 9, 2025). Liquid Glass is a translucent, dynamic material that reflects and refracts surrounding content while transforming to bring focus to user tasks. This unified design language spans iOS 26, iPadOS 26, macOS Tahoe 26, watchOS 26, tvOS 26, and visionOS 26.
Liquid Glass features real-time light bending (lensing), specular highlights responding to device motion, adaptive shadows, and interactive behaviors. The material continuously adapts to background content, light conditions, and user interactions, creating depth and hierarchy between foreground controls and background content.
Key Characteristics:
- Lensing: Bends and concentrates light in real-time (vs. traditional blur that scatters light)
- Materialization: Elements appear by gradually modulating light bending
- Fluidity: Gel-like flexibility with instant touch responsiveness
- Morphing: Dynamic transformation between control states
- Adaptivity: Multi-layer composition adjusting to content, color scheme, and size
Part 1: Foundation & Basics
1.1 Core Concepts
Design Philosophy Liquid Glass is exclusively for the navigation layer that floats above app content. Never apply to content itself (lists, tables, media). This maintains clear visual hierarchy: content remains primary while controls provide functional overlay.
Material Variants
| Variant | Use Case | Transparency | Adaptivity |
|---|---|---|---|
.regular | Default for most UI | Medium | Full - adapts to any content |
.clear | Media-rich backgrounds | High | Limited - requires dimming layer |
.identity | Conditional disable | None | N/A - no effect applied |
When to Use Each Variant:
- Regular: Toolbars, buttons, navigation bars, tab bars, standard controls
- Clear: Small floating controls over photos/maps with bold foreground content
- Identity: Conditional toggling (e.g.,
glassEffect(isEnabled ? .regular : .identity))
Design Requirements for Clear Variant (all must be met):
- Element sits over media-rich content
- Content won't be negatively affected by dimming layer
- Content above glass is bold and bright
1.2 Basic Implementation
Simple Glass Effect
import SwiftUI struct BasicGlassView: View { var body: some View { Text("Hello, Liquid Glass!") .padding() .glassEffect() // Default: .regular variant, .capsule shape } }
With Explicit Parameters
Text("Custom Glass") .padding() .glassEffect(.regular, in: .capsule, isEnabled: true)
API Signature
func glassEffect<S: Shape>( _ glass: Glass = .regular, in shape: S = DefaultGlassEffectShape, isEnabled: Bool = true ) -> some View
1.3 Glass Type Modifiers
Core Structure
struct Glass { static var regular: Glass static var clear: Glass static var identity: Glass func tint(_ color: Color) -> Glass func interactive() -> Glass }
Tinting
// Basic tint Text("Tinted") .padding() .glassEffect(.regular.tint(.blue)) // With opacity Text("Subtle Tint") .padding() .glassEffect(.regular.tint(.purple.opacity(0.6)))
Purpose: Convey semantic meaning (primary action, state), NOT decoration. Use selectively for call-to-action only.
Interactive Modifier (iOS only)
Button("Tap Me") { // action } .glassEffect(.regular.interactive())
Behaviors Enabled:
- Scaling on press
- Bouncing animation
- Shimmering effect
- Touch-point illumination that radiates to nearby glass
- Response to tap and drag gestures
Method Chaining
.glassEffect(.regular.tint(.orange).interactive()) .glassEffect(.clear.interactive().tint(.blue)) // Order doesn't matter
1.4 Custom Shapes
Available Shapes
// Capsule (default) .glassEffect(.regular, in: .capsule) // Circle .glassEffect(.regular, in: .circle) // Rounded Rectangle .glassEffect(.regular, in: RoundedRectangle(cornerRadius: 16)) // Container-concentric (aligns with container corners) .glassEffect(.regular, in: .rect(cornerRadius: .containerConcentric)) // Ellipse .glassEffect(.regular, in: .ellipse) // Custom shape conforming to Shape protocol struct CustomShape: Shape { func path(in rect: CGRect) -> Path { // Custom path logic } } .glassEffect(.regular, in: CustomShape())
Corner Concentricity Maintains perfect alignment between elements and containers across devices:
// Automatically matches container/window corners RoundedRectangle(cornerRadius: .containerConcentric, style: .continuous)
1.5 Text & Icons with Glass
Text Rendering
Text("Glass Text") .font(.title) .bold() .foregroundStyle(.white) // High contrast for legibility .padding() .glassEffect()
Text on glass automatically receives vibrant treatment - adjusts color, brightness, saturation based on background.
Icon Rendering
Image(systemName: "heart.fill") .font(.largeTitle) .foregroundStyle(.white) .frame(width: 60, height: 60) .glassEffect(.regular.interactive())
Labels
Label("Settings", systemImage: "gear") .labelStyle(.iconOnly) .padding() .glassEffect()
1.6 Accessibility Support
Automatic Adaptation - No code changes required:
- Reduced Transparency: Increases frosting for clarity
- Increased Contrast: Stark colors and borders
- Reduced Motion (improved in 26.4): Tones down animations and elastic effects; the 26.4 release made this "more reliably" dampen Liquid Glass-specific animations
- iOS 26.1+ Tinted Mode: User-controlled opacity increase (Settings → Display & Brightness → Liquid Glass). Choices are Clear (default) and Tinted (more opaque)
- iOS 26.2+ Lock Screen clock: Long-press the Lock Screen → Customize → tap the clock for Glass or Solid rendering; 26.4 added an opacity slider
- iOS 26.4+ Reduce Bright Effects: Settings → Accessibility → Display & Text Size — "minimizes highlighting and flashing when interacting with onscreen elements, such as buttons or the keyboard"
Gotcha: The Display & Brightness → Liquid Glass menu only unlocks when Reduce Transparency is OFF — the two settings are mutually exclusive in the UI.
Environment Values
@Environment(\.accessibilityReduceTransparency) var reduceTransparency @Environment(\.accessibilityReduceMotion) var reduceMotion var body: some View { Text("Accessible") .padding() .glassEffect(reduceTransparency ? .identity : .regular) }
Best Practice: Let system handle accessibility automatically. Don't override unless absolutely necessary.
Part 2: Intermediate Techniques
2.1 GlassEffectContainer
Purpose
- Combines multiple Liquid Glass shapes into unified composition
- Improves rendering performance by sharing sampling region
- Enables morphing transitions between glass elements
- Critical Rule: Glass cannot sample other glass; container provides shared sampling region
Basic Usage
GlassEffectContainer { HStack(spacing: 20) { Image(systemName: "pencil") .frame(width: 44, height: 44) .glassEffect(.regular.interactive()) Image(systemName: "eraser") .frame(width: 44, height: 44) .glassEffect(.regular.interactive()) } }
With Spacing Control
GlassEffectContainer(spacing: 40.0) { // Glass elements within 40 points will morph together ForEach(icons) { icon in IconView(icon) .glassEffect() } }
Spacing Parameter: Controls morphing threshold - elements within this distance visually blend and morph together during transitions.
API Signature
struct GlassEffectContainer<Content: View>: View { init(spacing: CGFloat? = nil, @ViewBuilder content: () -> Content) init(@ViewBuilder content: () -> Content) }
2.2 Morphing Transitions with glassEffectID
Requirements for Morphing:
- Elements in same
GlassEffectContainer - Each view has
glassEffectIDwith shared namespace - Views conditionally shown/hidden trigger morphing
- Animation applied to state changes
Basic Morphing Setup
struct MorphingExample: View { @State private var isExpanded = false @Namespace private var namespace var body: some View { GlassEffectContainer(spacing: 30) { Button(isExpanded ? "Collapse" : "Expand") { withAnimation(.bouncy) { isExpanded.toggle() } } .glassEffect() .glassEffectID("toggle", in: namespace) if isExpanded { Button("Action 1") { } .glassEffect() .glassEffectID("action1", in: namespace) Button("Action 2") { } .glassEffect() .glassEffectID("action2", in: namespace) } } } }
API Signature
func glassEffectID<ID: Hashable>( _ id: ID, in namespace: Namespace.ID ) -> some View
Advanced Morphing Pattern - Expandable Action Menu
struct ActionButtonsView: View { @State private var showActions = false @Namespace private var namespace var body: some View { ZStack { Image("background") .resizable() .ignoresSafeArea() GlassEffectContainer(spacing: 30) { VStack(spacing: 30) { if showActions { actionButton("rotate.right") .glassEffectID("rotate", in: namespace) } HStack(spacing: 30) { if showActions { actionButton("circle.lefthalf.filled") .glassEffectID("contrast", in: namespace) } actionButton(showActions ? "xmark" : "slider.horizontal.3") { withAnimation(.bouncy) { showActions.toggle() } } .glassEffectID("toggle", in: namespace) if showActions { actionButton("flip.horizontal") .glassEffectID("flip", in: namespace) } } if showActions { actionButton("crop") .glassEffectID("crop", in: namespace) } } } } } @ViewBuilder func actionButton(_ systemImage: String, action: (() -> Void)? = nil) -> some View { Button { action?() } label: { Image(systemName: systemImage) .frame(width: 44, height: 44) } .buttonStyle(.glass) .buttonBorderShape(.circle) } }
2.3 Glass Button Styles
Button Style Types
| Style | Appearance | Use Case |
|---|---|---|
.glass | Translucent, see-through | Secondary actions |
.glassProminent | Opaque, no background show-through | Primary actions |
Basic Implementation
// Secondary action Button("Cancel") { } .buttonStyle(.glass) // Primary action Button("Save") { } .buttonStyle(.glassProminent) .tint(.blue)
With Customization
Button("Action") { } .buttonStyle(.glass) .tint(.purple) .controlSize(.large) .buttonBorderShape(.circle)
Available Control Sizes
.controlSize(.mini) .controlSize(.small) .controlSize(.regular) // Default .controlSize(.large) .controlSize(.extraLarge) // New in iOS 26
Border Shapes
.buttonBorderShape(.capsule) // Default .buttonBorderShape(.roundedRectangle(radius: 8)) .buttonBorderShape(.circle)
2.4 Toolbar Integration
Automatic Glass Styling Toolbars automatically receive Liquid Glass treatment in iOS 26:
NavigationStack { ContentView() .toolbar { ToolbarItem(placement: .cancellationAction) { Button("Cancel", systemImage: "xmark") { } } ToolbarItem(placement: .confirmationAction) { Button("Done", systemImage: "checkmark") { } } } }
Automatic Behaviors:
- Prioritizes symbols over text
.confirmationActionautomatically gets.glassProminentstyle- Floating glass appearance
- Grouped layouts with visual separation
Toolbar Grouping with Spacing
.toolbar { ToolbarItemGroup(placement: .topBarTrailing) { Button("Draw", systemImage: "pencil") { } Button("Erase", systemImage: "eraser") { } } ToolbarSpacer(.fixed, spacing: 20) // New in iOS 26 ToolbarItem(placement: .topBarTrailing) { Button("Save", systemImage: "checkmark") { } .buttonStyle(.glassProminent) } }
ToolbarSpacer Types
ToolbarSpacer(.fixed, spacing: 20) // Fixed space ToolbarSpacer(.flexible) // Flexible space (pushes items apart)
2.5 TabView with Liquid Glass
Basic TabView Automatically adopts Liquid Glass when compiled with Xcode 26:
TabView { Tab("Home", systemImage: "house") { HomeView() } Tab("Settings", systemImage: "gear") { SettingsView() } }
Search Tab Role Creates floating search button at bottom-right (reachability optimization):
struct ContentView: View { @State private var searchText = "" var body: some View { TabView { Tab("Home", systemImage: "house") { HomeView() } Tab("Search", systemImage: "magnifyingglass", role: .search) { NavigationStack { SearchView() } } } .searchable(text: $searchText) } }
Tab Bar Minimize Behavior
TabView { // tabs... } .tabBarMinimizeBehavior(.onScrollDown) // Collapses during scroll
Options:
.automatic- System determines.onScrollDown- Minimizes when scrolling.never- Always full size
Tab View Bottom Accessory Adds persistent glass view above tab bar:
TabView { // tabs... } .tabViewBottomAccessory { HStack { Image(systemName: "play.fill") Text("Now Playing") Spacer() } .padding() }
2.6 Sheet Presentations
Automatic Glass Background Sheets in iOS 26 automatically receive inset Liquid Glass background:
.sheet(isPresented: $showSheet) { SheetContent() .presentationDetents([.medium, .large]) }
Sheet Morphing from Toolbar
struct ContentView: View { @Namespace private var transition @State private var showInfo = false var body: some View { NavigationStack { ContentView() .toolbar { ToolbarItem(placement: .bottomBar) { Button("Info", systemImage: "info") { showInfo = true } .matchedTransitionSource(id: "info", in: transition) } } .sheet(isPresented: $showInfo) { InfoSheet() .navigationTransition(.zoom(sourceID: "info", in: transition)) } } } }
Gotchas worth knowing:
NavigationStack(orNavigationSplitView) is required even when the source button lives in a bottom bar — the zoom transition is wired through the navigation context (Nil Coalescing).- The source doesn't have to be in the bottom bar. Any
.matchedTransitionSourceview works as the morph origin — toolbar buttons, custom floating buttons, even cells (SerialCoder). - Declare
@Namespaceonce at the parent, then reuse it across child views — per-screen namespaces fight each other and break the zoom continuity (Sagar Unagar). - The transition can still be glitchy in early betas. As of iOS 26 beta 3, Apple was still ironing out edge cases on rotation and quick re-presentation.
2.7 NavigationSplitView Integration
Automatic Floating Sidebar
NavigationSplitView { List(items) { item in NavigationLink(item.name, value: item) } .navigationTitle("Items") } detail: { DetailView() }
Sidebar automatically receives floating Liquid Glass with ambient reflection.
Part 3: Advanced Implementation
3.1 glassEffectUnion
Purpose: Manually combine glass effects that are too distant to merge via spacing alone.
API Signature
func glassEffectUnion<ID: Hashable>( id: ID, namespace: Namespace.ID ) -> some View
Example
struct UnionExample: View { @Namespace var controls var body: some View { GlassEffectContainer { VStack(spacing: 0) { Button("Edit") { } .buttonStyle(.glass) .glassEffectUnion(id: "tools", namespace: controls) Spacer().frame(height: 100) // Large gap Button("Delete") { } .buttonStyle(.glass) .glassEffectUnion(id: "tools", namespace: controls) } } } }
Apple Maps Pattern (vertically stacked dual-button control) The most-cited reference implementation is Donny Wals' Apple Maps clone — a single glass shape containing two action buttons (zoom in / zoom out). The trick is overriding the default tint to keep the shape looking like a single piece of frosted hardware:
GlassEffectContainer { VStack(spacing: 1) { Button { } label: { Image(systemName: "plus") } .glassEffectUnion(id: "zoom", namespace: ns) Divider().frame(width: 24) Button { } label: { Image(systemName: "minus") } .glassEffectUnion(id: "zoom", namespace: ns) } .tint(Color.white.opacity(0.8)) // Override default tint }
Rules of thumb:
glassEffectUnionis for distance-spanning grouping — when two glass surfaces are too far apart for the container'sspacingto merge them automatically.- Set the same
idon every view that should share a shape; differentids in the same namespace render as separate shapes. - Apple's own documentation on
glassEffectUnionis thin — community writeups (Donny Wals, artemnovichkov's recovered Xcode docs) are currently the most complete references.
3.2 glassEffectTransition
API Signature
func glassEffectTransition( _ transition: GlassEffectTransition, isEnabled: Bool = true ) -> some View enum GlassEffectTransition { case identity // No changes case matchedGeometry // Matched geometry transition (default) case materialize // Material appearance transition }
3.3 Complex Multi-Element Compositions
Floating Action Cluster
struct FloatingActionCluster: View { @State private var isExpanded = false @Namespace private var namespace let actions = [ ("home", Color.purple), ("pencil", Color.blue), ("message", Color.green), ("envelope", Color.orange) ] var body: some View { ZStack { ContentView() VStack { Spacer() HStack { Spacer() cluster .padding() } } } } var cluster: some View { GlassEffectContainer(spacing: 20) { VStack(spacing: 12) { if isExpanded { ForEach(actions, id: \.0) { action in actionButton(action.0, color: action.1) .glassEffectID(action.0, in: namespace) } } Button { withAnimation(.bouncy(duration: 0.4)) { isExpanded.toggle() } } label: { Image(systemName: isExpanded ? "xmark" : "plus") .font(.title2.bold()) .frame(width: 56, height: 56) } .buttonStyle(.glassProminent) .buttonBorderShape(.circle) .tint(.blue) .glassEffectID("toggle", in: namespace) } } } func actionButton(_ icon: String, color: Color) -> some View { Button { // action } label: { Image(systemName: icon) .font(.title3) .frame(width: 48, height: 48) } .buttonStyle(.glass) .buttonBorderShape(.circle) .tint(color) } }
3.4 Symbol Effects Integration
Smooth Icon Transitions
struct SymbolGlassButton: View { @State private var isLiked = false var body: some View { Button { isLiked.toggle() } label: { Image(systemName: isLiked ? "heart.fill" : "heart") .font(.title) .frame(width: 60, height: 60) } .glassEffect(.regular.interactive()) .contentTransition(.symbolEffect(.replace)) .tint(isLiked ? .red : .primary) } }
3.5 Performance Optimization
Best Practices:
- Always Use GlassEffectContainer for Multiple Elements
// ✅ GOOD - Efficient rendering GlassEffectContainer { HStack { Button("Edit") { }.glassEffect() Button("Delete") { }.glassEffect() } } // ❌ BAD - Inefficient, inconsistent sampling HStack { Button("Edit") { }.glassEffect() Button("Delete") { }.glassEffect() }
- Conditional Glass with .identity
.glassEffect(shouldShowGlass ? .regular : .identity)
No layout recalculation when toggling.
-
Limit Continuous Animations Let glass rest in steady states.
-
Test on Older Devices
- iPhone 11-13: May show lag
- Profile with Instruments for GPU usage
- Monitor thermal performance
3.6 Dynamic Glass Adaptation
Automatic Color Scheme Switching Glass automatically adapts between light/dark based on background:
ScrollView { Color.black.frame(height: 400) // Glass becomes light Color.white.frame(height: 400) // Glass becomes dark } .safeAreaInset(edge: .bottom) { ControlPanel() .glassEffect() // Automatically adapts }
Adaptive Behaviors:
- Small elements (nav bars, tab bars): Flip between light/dark
- Large elements (sidebars, menus): Adapt but don't flip (would be jarring)
- Shadows: Opacity increases over text, decreases over white backgrounds
- Tint: Adjusts hue, brightness, saturation for legibility
3.7 Gesture Integration
Drag Gesture with Glass
struct DraggableGlassButton: View { @State private var offset = CGSize.zero @State private var isDragging = false var body: some View { Button("Drag Me") { } .glassEffect(.regular.interactive()) .offset(offset) .scaleEffect(isDragging ? 1.1 : 1.0) .gesture( DragGesture() .onChanged { value in isDragging = true offset = value.translation } .onEnded { _ in withAnimation(.spring(response: 0.3, dampingFraction: 0.6)) { isDragging = false offset = .zero } } ) } }
Part 4: Edge Cases & Advanced Topics
4.1 Handling Complex Background Content
The Readability Problem Liquid Glass over busy, colorful, or animated content causes readability issues.
Solution 1: Gradient Fade
struct TabBarFadeModifier: ViewModifier { let fadeLocation: CGFloat = 0.4 let opacity: CGFloat = 0.85 let backgroundColor: Color = Color(.systemBackground) func body(content: Content) -> some View { GeometryReader { geometry in ZStack { content if geometry.safeAreaInsets.bottom > 10 { let dynamicHeight = geometry.safeAreaInsets.bottom VStack { Spacer() LinearGradient( gradient: Gradient(stops: [ .init(color: .clear, location: 0.0), .init(color: backgroundColor.opacity(opacity), location: fadeLocation) ]), startPoint: .top, endPoint: .bottom ) .frame(height: dynamicHeight) .allowsHitTesting(false) .offset(y: geometry.safeAreaInsets.bottom) } } } } } } extension View { func deliquify() -> some View { self.modifier(TabBarFadeModifier()) } }
Solution 2: Strategic Tinting
.glassEffect(.regular.tint(.purple.opacity(0.8)))
Solution 3: Background Dimming
ZStack { BackgroundImage() .overlay(Color.black.opacity(0.3)) // Subtle dimming GlassControls() .glassEffect(.clear) }
4.2 Glass Layering Guidelines
Avoid Glass-on-Glass
// ❌ BAD - Confusing visual hierarchy VStack { HeaderView().glassEffect() ContentView().glassEffect() FooterView().glassEffect() } // ✅ GOOD - Clear separation ZStack { ContentView() // No glass HeaderView().glassEffect() // Single floating layer }
Proper Layering Philosophy:
- Content layer (bottom) - No glass
- Navigation layer (middle) - Liquid Glass
- Overlay layer (top) - Vibrancy and fills on glass
4.3 Platform Differences
| Platform | Adaptations |
|---|---|
| iOS | Floating tab bars, bottom search placement |
| iPadOS | Floating sidebars, ambient reflection, larger shadows |
| macOS | Concentric window corners, adaptive search bars, taller controls |
| watchOS | Location-aware widgets, fluid navigation |
| tvOS | Focused glass effects, directional highlights |
Minimum Requirements:
- iOS 26.0+, iPadOS 26.0+, macOS Tahoe (26.0)+, watchOS 26.0+, tvOS 26.0+, visionOS 26.0+
- Xcode 26.0+
Device Support:
- iOS 26: iPhone 11 or iPhone SE (2nd gen) or later
- Older devices: Receive frosted glass fallback with reduced effects
4.4 Backward Compatibility
Automatic Adoption Simply recompile with Xcode 26 - no code changes required for basic adoption.
Temporary Opt-Out (expires iOS 27)
<!-- Info.plist --> <key>UIDesignRequiresCompatibility</key> <true/>
Custom Compatibility Extension
extension View { @ViewBuilder func glassedEffect( in shape: some Shape = Capsule(), interactive: Bool = false ) -> some View { if #available(iOS 26.0, *) { let glass = interactive ? Glass.regular.interactive() : .regular self.glassEffect(glass, in: shape) } else { self .background( shape .fill(.ultraThinMaterial) .overlay( LinearGradient( colors: [.white.opacity(0.3), .clear], startPoint: .topLeading, endPoint: .bottomTrailing ) ) .overlay(shape.stroke(.white.opacity(0.2), lineWidth: 1)) ) } } }
4.5 UIKit Integration
UIGlassEffect
import UIKit let glassEffect = UIGlassEffect( glass: .regular, isInteractive: true ) let effectView = UIVisualEffectView(effect: glassEffect) effectView.frame = CGRect(x: 0, y: 0, width: 200, height: 50) view.addSubview(effectView)
UIKit + SwiftUI Hybrid Adoption
Most production iOS apps aren't pure SwiftUI — they're UIKit shells hosting SwiftUI screens (or vice versa). The Grow team's writeup with Fatbobman is the deepest public reference on the precise traps that bite hybrid apps porting to Liquid Glass:
// 1. Stop UIBarButtonItem from drawing its own background // when the SwiftUI content inside already has .glassEffect() let item = UIBarButtonItem(customView: hostingController.view) item.hidesSharedBackground = true // 2. Let the UIHostingController size itself from its SwiftUI content // — otherwise the toolbar item collapses to zero width hostingController.sizingOptions = .intrinsicContentSize // 3. Defend dynamic-width nav items against truncation // when the title or label changes length at runtime hostingController.view.setContentCompressionResistancePriority( .required, for: .horizontal )
Why each step matters:
hidesSharedBackground = true— without it, you get two glass surfaces stacked: the system bar background and your inner SwiftUI glass. This produces the visual "glass-on-glass" artifact Apple's HIG warns against.sizingOptions = .intrinsicContentSize—UIHostingControllerdefaults to filling the available bounds. Bar items need to size to their content, not their container.- Content compression resistance — bar buttons whose width changes (e.g., switching between "Edit" and "Cancel") will be truncated by the system layout pass unless you raise their priority.
CABackdropLayer caveats — Apple's underlying glass effect uses CABackdropLayer under the hood. Side effects worth knowing: it samples the layer tree behind it, so layers parented above your glass (overlays, snapshot views) will not appear in the refraction; and toggling isHidden on a backdrop layer mid-animation can cause a one-frame flash.
Core Text "glass text" trick — for marketing/headline surfaces where you want the type itself to be glass, the Grow team uses Core Text to extract glyph paths, then applies .glassEffect(.clear, in: glyphPath):
let line = CTLineCreateWithAttributedString(attributedString) let glyphPath = /* extract via CTRunGetGlyphs + CTFontCreatePathForGlyph */ SomeView().glassEffect(.clear, in: Path(glyphPath))
This is expensive — cache the resulting path; don't recompute per frame.
4.6 Known Issues & Workarounds
Issue 1: Interactive Shape Mismatch
Problem: .glassEffect(.regular.interactive(), in: RoundedRectangle()) responds with Capsule shape
Workaround: Use .buttonStyle(.glass) for buttons instead
Issue 2: glassProminent Circle Artifacts Workaround:
Button("Action") { } .buttonStyle(.glassProminent) .buttonBorderShape(.circle) .clipShape(Circle()) // Fixes artifacts
4.7 Performance Implications
Battery Impact
- iOS 26: 13% battery drain vs. 1% in iOS 18 (iPhone 16 Pro Max testing)
- Increased heat generation
- Higher CPU/GPU load on older devices
Optimization Strategies:
- Use
GlassEffectContainerfor multiple elements - Limit continuous animations
- Let glass rest in steady states
- Test on 3-year-old devices
- Profile with Instruments
Part 5: Best Practices & Design Patterns
5.1 When to Use Glass vs Traditional UI
Use Liquid Glass for:
- Navigation bars and toolbars
- Tab bars and bottom accessories
- Floating action buttons
- Sheets, popovers, and menus
- Context-sensitive controls
- System-level alerts
Avoid Liquid Glass for:
- Content layer (lists, tables, media)
- Full-screen backgrounds
- Scrollable content
- Stacked glass layers
- Every UI element
Apple's Guidance: "Liquid Glass is best reserved for the navigation layer that floats above the content of your app."
5.2 Design Principles
Hierarchy
- Content = Primary
- Glass controls = Secondary functional layer
- Overlay fills/vibrancy = Tertiary
Contrast Management
- Maintain 4.5:1 minimum contrast ratio
- Test legibility across backgrounds
- Use vibrant text on glass
- Add subtle borders for definition
Tinting Philosophy
- Use selectively for primary actions
- Avoid tinting everything
- Tint conveys meaning, not decoration
5.3 Anti-Patterns
Visual Anti-Patterns:
- Overuse - glass everywhere
- Glass-on-glass stacking
- Content layer glass
- Tinting everything
- Breaking concentricity
Technical Anti-Patterns:
- Custom opacity bypassing accessibility
- Ignoring safe areas
- Hard-coded color schemes
- Mixing Regular and Clear variants
- Multiple separate glass effects without container
Usability Anti-Patterns:
- Busy backgrounds without dimming
- Insufficient contrast
- Excessive animations
- Breaking iOS conventions
- Prioritizing aesthetics over usability
Part 6: API Quick Reference
Core Modifiers
// Basic glass effect .glassEffect() -> some View .glassEffect(_ glass: Glass, in shape: some Shape, isEnabled: Bool) -> some View // Glass effect ID for morphing .glassEffectID<ID: Hashable>(_ id: ID, in namespace: Namespace.ID) -> some View // Glass effect union .glassEffectUnion<ID: Hashable>(id: ID, namespace: Namespace.ID) -> some View // Glass effect transition .glassEffectTransition(_ transition: GlassEffectTransition, isEnabled: Bool) -> some View
Glass Types
Glass.regular // Default adaptive variant Glass.clear // High transparency variant Glass.identity // No effect // Modifiers .tint(_ color: Color) // Add color tint .interactive() // Enable interactive behaviors (iOS only)
Button Styles
.buttonStyle(.glass) // Translucent glass button .buttonStyle(.glassProminent) // Opaque prominent button
Container
GlassEffectContainer { // Content with .glassEffect() views } GlassEffectContainer(spacing: CGFloat) { // Content with controlled morphing distance }
Toolbar & Navigation
.toolbar { } // Automatic glass styling ToolbarSpacer(.fixed, spacing: CGFloat) ToolbarSpacer(.flexible) .badge(Int) // Badge count .sharedBackgroundVisibility(.hidden) // Hide glass background
TabView
.tabBarMinimizeBehavior(.onScrollDown) .tabBarMinimizeBehavior(.automatic) .tabBarMinimizeBehavior(.never) .tabViewBottomAccessory { }
Part 7: Point-Release Changelog
A version-by-version log of every Liquid Glass-relevant change between WWDC 2025 and May 2026. Useful when you need to know "what's the minimum iOS that supports X?" without grepping release notes.
iOS 26.0 — September 2025
Initial release. The full Liquid Glass API surface as shipped at WWDC 2025:
glassEffect(),glassEffectID,glassEffectUnion,glassEffectTransitionGlassEffectContainer.buttonStyle(.glass),.buttonStyle(.glassProminent)Glass.regular,Glass.clear,Glass.identity- TabView accessory,
tabBarMinimizeBehavior matchedTransitionSource+.navigationTransition(.zoom)(technically iOS 18, but received the Liquid Glass coat of paint here)- UIKit
UIGlassEffect,UIBarButtonItem.hidesSharedBackground - AppKit
NSGlassEffectView,NSGlassEffectContainerView
iOS 26.1 — November 2025
- Settings → Display & Brightness → Liquid Glass added with two options: Clear (default) and Tinted (more opaque/contrasty).
- Mutually exclusive with Reduce Transparency — the menu only appears when Reduce Transparency is OFF.
iOS 26.2 — 15 December 2025
Three Liquid Glass-relevant changes:
- Popup menu / control animations updated to match the original WWDC25 demo (more bounce, more fluidity than 26.0–26.1 shipped with).
- Lock Screen clock customization gained Glass and Solid options (long-press → Customize → tap clock). Directly addresses the most-cited Lock Screen legibility complaint.
- Measure app's Level tool refreshed with Liquid Glass — numbers interact with the grid.
Context: Bloomberg's Mark Gurman reported on 3 Dec 2025 that Alan Dye — VP of Human Interface Design since 2015, the design VP most identified with Liquid Glass — left Apple to become Chief Design Officer at Meta on 31 Dec 2025. He was succeeded by Stephen Lemay, a 26-year Apple design veteran. Tim Cook described Lemay as having "played a key role in the design of every major Apple interface since 1999."
iOS 26.3 — 11 February 2026
No Liquid Glass-specific changes. This was the EU DMA-driven release: Transfer to Android, Limit Precise Location, NFC for third-party accessory pairing, and 29 security patches. iOS 26.3.1 (4 March 2026) added Studio Display XDR support and bug fixes — also no Liquid Glass changes.
iOS 26.4 — April 2026
- New Accessibility toggle: Reduce Bright Effects (Settings → Accessibility → Display & Text Size). Apple's description: "Minimize highlighting and flashing when interacting with onscreen elements, such as buttons or the keyboard." Specifically targets the bright "flash" response on tap.
- Improved Reduce Motion — now "more reliably reduces the animations of Liquid Glass for users sensitive to screen motion" (Apple release notes).
- Lock Screen clock opacity slider added for finer time-customization control.
- Apple's updated Liquid Glass design gallery published on 6 April 2026 with 19 new third-party reference apps (AllTrails, CARROT Weather, Fantastical, Trello, Monzo, Le Monde, Channel 4, GoodLinks, etc.).
iOS 26.5 — May 2026 (public beta)
Minor; no announced Liquid Glass changes. Apple is reportedly already focused on iOS 27.
Looking forward — WWDC 2026 (8 June 2026)
Per Bloomberg/Mark Gurman's Power On newsletter (10 May 2026), confirmed via MacRumors, Macworld, MacDailyNews, and 9to5Mac:
- macOS 27 will receive a "slight redesign" — tuned shadows, opacity, and transparency behavior. Gurman's framing: "the changes to macOS are meant to make Liquid Glass look the way Apple's design team intended it to from the start. Last year's operating systems didn't necessarily suffer from design problems, I'm told, but rather a not-completely-baked implementation from Apple's software engineering team."
- Liquid Glass is not going away. AppleInsider's one-year review and the macOS 27 leak both confirm the strategy: per-surface dials (Tinted, Reduce Bright Effects, Lock Screen opacity slider) rather than a system-wide opt-out.
- iOS 27 / iPadOS 27 are expected to receive interface tweaks of similar scope.
- Apple may add a system-wide Liquid Glass intensity slider (currently controls are per-surface).
Treat all of the above as forward-looking until the WWDC keynote.
Part 8: Web & Cross-Platform Approximations
Liquid Glass has triggered an ecosystem of CSS+SVG and shader-based reproductions for the web, Flutter, Vue, and Android. These are visual approximations only — not Apple APIs, not subject to Apple's HIG, and they don't run real Metal shaders against the composited framebuffer the way the native effect does.
If you're building a marketing site or cross-platform app and want the look, this section is for you. If you're an iOS engineer building a real app, skip it — use the native APIs.
The Three Reference Web Implementations
| Resource | Approach | Notes |
|---|---|---|
| kube.io — "Liquid Glass in the Browser: Refraction with CSS and SVG" | Physics-based 127-sample radial displacement maps derived from Snell's Law | The most rigorous. Pre-computes the displacement map; Chromium-only because it uses SVG filters as backdrop-filter. |
| ekino-france — "Liquid Glass in CSS (and SVG)" | Linear-gradient displacement map + blurred mask + chromatic aberration | Honest about limitations. Good middle-ground complexity. |
| LogRocket — "How to create Liquid Glass effects with CSS and SVG" | React + Tailwind tutorial with Figma asset workflow | GSAP-driven animated demo on CodePen. Easiest to adapt. |
Open-Source Libraries
nikdelvin/liquid-glass— Production-style web components. Safari fallback to glassmorphism.archisvaze/liquid-glass— Interactive demo with adjustable IOR, bezel width, thickness; WebGL fallback for non-Chromium.shuding/liquid-glass— Pure JS+SVG.mks2508/liquid-svg-glass— React library with chromatic aberration.- Flutter:
colbymaloy/flutter_liquid_glass,liquid_glass_renderer(shader-based). - Android:
AndroidLiquidGlassView— actual refraction + dispersion via custom shader.
Things to internalize before shipping a web "Liquid Glass" effect
- These are approximations only. Apple's implementation runs Metal shaders against the actual composited framebuffer with real-time adaptive shadow + specular highlights driven by device motion. The web versions are stylized displacement maps.
- Browser support is Chromium-dominated. SVG filters as
backdrop-filterare not reliable in Safari or Firefox — ironic given the effect's origin. - Per-element displacement maps don't scale to dynamic content sizes without rebuild cost. This is a known performance ceiling for the SVG approach.
- Don't call it "Liquid Glass" in a way that implies Apple endorsement if your app ships outside Apple's platforms. The name has trademark sensitivity and the gallery placement matters to Apple.
Sources that invent APIs
Watch out for low-trust content. A few SEO-driven posts (e.g. some swiftprogramming.com tutorials) reference modifiers like .background(.liquidGlassUltra) that do not exist in real SwiftUI. Verify any API claim against Apple's official docs before adopting it.
Part 9: Community Reception
Liquid Glass has had a genuinely bimodal reception. Both poles are worth knowing about — partly so you can make informed design choices, partly because users will arrive at your app with strong priors in either direction.
The praise
- ADC 2026 wins. Liquid Glass took home four awards at the 105th ADC Annual Awards (announced 14 May 2026): a Gold Cube in "Interactive / UX / UI," a Silver Cube in "Experiential Design / Digital Experiences," and two Bronze Cubes in "Experiential Design / Consumer Experience" and "Innovation." Apple won six Gold Cubes total at the ceremony.
- "Makes the iPhone feel faster" — the most-repeated positive sentiment in MacRumors threads and Apple Community discussions. The fluid morphing and touch-point illumination create a sense of responsiveness even when underlying performance is unchanged.
- Macworld: "Sorry haters, Liquid Glass on the Mac isn't going anywhere." Confirms macOS 27 will refine, not roll back.
- Apple's design gallery has grown from 16 apps at launch to 35+ across the original and 2026 refresh galleries — meaningful third-party adoption, not just Apple's own apps.
The critique
- Legibility on dark mode. PiunikaWeb's "The Liquid Glass glow in iOS 26" and the MacRumors forum thread "Apple need to tweak the Liquid Glass Design badly" both single out dark-mode glare on the Lock Screen and Control Center as the strongest legibility complaint. Apple's response was the 26.2 Lock Screen clock Glass/Solid options.
- Animation lag on older devices. iPhone 11–13 users report visible frame drops during heavy Liquid Glass animations. The Reduce Motion improvements in 26.4 help, but the underlying compute cost is real.
- Battery impact. Early third-party testing (iPhone 16 Pro Max) suggested ~13% battery drain attributable to Liquid Glass rendering vs. ~1% baseline on iOS 18. Apple has not published official numbers; treat third-party measurements as directional.
- "Barbie phone" aesthetics. A subset of users find the bright, candy-like refraction tonally inappropriate for a productivity device. This is taste, but it's a real signal.
- Mandatory adoption. AppleInsider's one-year review argues Apple has signaled it will not provide a system-wide opt-out switch — the per-surface dials (Tinted, Reduce Bright Effects) are the strategy. Users who want flat UI will not get one.
- Gallery aspirationalism. Rahul Roy's critique — "Apple's Liquid Glass Gallery Is a Showcase of 12 Apps in a Store of Millions" — argues the gallery functions as implicit pressure on developers, particularly cross-platform/Flutter/React Native teams who can't easily replicate the native effect.
What this means for your app
- Design for both ends of the accessibility spectrum. Users with Reduce Transparency, Increased Contrast, Reduce Motion, or Reduce Bright Effects enabled are not edge cases — they're a meaningful slice of your install base.
- Don't over-tint. The "Barbie phone" complaint is downstream of decorative tint use. Reserve
.tint()for primary action and state, never for branding alone. - Performance-test on a 3-year-old device. If your app drops frames on iPhone 13, you're contributing to the negative narrative, not the positive one.
- Honour the user's chosen dial. Read
accessibilityReduceTransparencyandaccessibilityReduceMotionand respect them — Apple's own apps now do so more aggressively after 26.4.
Resources
Official Apple Documentation
WWDC 2025 Sessions:
- Session 219: Meet Liquid Glass
- Session 323: Build a SwiftUI app with the new design
- Session 356: Get to know the new design system
Sample Code:
- Landmarks: Building an app with Liquid Glass
- Refining toolbar glass effects
Community Resources
GitHub Repositories:
- mertozseven/LiquidGlassSwiftUI
- GonzaloFuentes28/LiquidGlassCheatsheet
- GetStream/awesome-liquid-glass
- artemnovichkov/iOS-26-by-Examples
- artemnovichkov/xcode-26-system-prompts — recovered Xcode 26 internal docs for SwiftUI/UIKit/AppKit/WidgetKit Liquid Glass
- carolhsiaoo/awesome-liquid-glass — cross-platform curated list (native + Figma + web + Flutter + Vue)
- jaikrishnavj/LiquidGlass-Handbook — 12+ interactive demo chapters
- sanjaynela/liquid-glass-ios-system — best
#availablefallback pattern
Developer Blogs — Foundational:
- Donny Wals: "Designing custom UI with Liquid Glass on iOS 26" — layer-not-base philosophy
- Donny Wals: "Grouping Liquid Glass components using glassEffectUnion" — best
glassEffectUnionreference - Donny Wals: "Exploring tab bars on iOS 26 with Liquid Glass"
- Swift with Majid: Glassifying tabs / toolbars / custom views series
- Create with Swift: "Exploring a new visual language: Liquid Glass"
Developer Blogs — Pattern-focused:
- Natalia Panferova (Nil Coalescing): "Presenting Liquid Glass sheets in SwiftUI on iOS 26" — canonical sheet-morph recipe
- Gabriel Theodoropoulos (SerialCoder): morphing glassEffectID + sheets-out-of-buttons walkthroughs
- Itsuki (Level Up Coding): "SwiftUI: Liquid Glass. From Basic to (A Little) Advance" — best intuition pump for container spacing
- Fatbobman + Grow team: "Grow on iOS 26 — Liquid Glass Adaptation in UIKit + SwiftUI Hybrid Architecture" — deepest hybrid writeup
- Khoa Pham (onmyway133): "How to morph liquid glass view transition"
- Douglas Hill: "Zoom transitions" — UIKit-side caveats
- Sagar Unagar: "Zoom Navigation Transitions in SwiftUI" — production app pattern
Web / Cross-Platform References (approximations only — not Apple APIs):
- kube.io — Liquid Glass in the Browser: Refraction with CSS and SVG
- ekino-france — Liquid Glass in CSS (and SVG)
- LogRocket — How to create Liquid Glass effects with CSS and SVG
Critique & Sentiment:
- AppleInsider: "iOS 26 review one year later" (May 2026) — definitive one-year retrospective
- AppleInsider: "Liquid Glass is controversial, but it just won a prestigious design award" (14 May 2026) — ADC 2026 wins
- MacRumors editorial: "iOS 26's Liquid Glass Design Draws Criticism From Users" (Sept 2025) — best summary of initial backlash
- PiunikaWeb: "The Liquid Glass glow in iOS 26 is here and so is the backlash" — strongest dark-mode legibility critique
- Macworld: "Sorry haters, Liquid Glass on the Mac isn't going anywhere" — macOS 27 direction
Key Takeaways:
- Reserve Liquid Glass for navigation layer only
- Always use GlassEffectContainer for multiple glass elements
- Test extensively with accessibility settings enabled
- Monitor performance on older devices
- Respect user preferences and system settings
- Prioritize content legibility over visual effects
- Use morphing transitions for smooth state changes
- Follow Apple's design guidelines and HIG