iOS 26 Liquid Glass: Comprehensive Swift/SwiftUI Reference

A complete guide to Apple's most significant design evolution since iOS 7

16 November 202530 min readAgent optimised version
AI-Ometerslop disclosure index
Mostly AI88%
 

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

VariantUse CaseTransparencyAdaptivity
.regularDefault for most UIMediumFull - adapts to any content
.clearMedia-rich backgroundsHighLimited - requires dimming layer
.identityConditional disableNoneN/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):

  1. Element sits over media-rich content
  2. Content won't be negatively affected by dimming layer
  3. 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:

  1. Elements in same GlassEffectContainer
  2. Each view has glassEffectID with shared namespace
  3. Views conditionally shown/hidden trigger morphing
  4. 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

StyleAppearanceUse Case
.glassTranslucent, see-throughSecondary actions
.glassProminentOpaque, no background show-throughPrimary 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
  • .confirmationAction automatically gets .glassProminent style
  • 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 (or NavigationSplitView) 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 .matchedTransitionSource view works as the morph origin — toolbar buttons, custom floating buttons, even cells (SerialCoder).
  • Declare @Namespace once 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:

  • glassEffectUnion is for distance-spanning grouping — when two glass surfaces are too far apart for the container's spacing to merge them automatically.
  • Set the same id on every view that should share a shape; different ids in the same namespace render as separate shapes.
  • Apple's own documentation on glassEffectUnion is 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:

  1. 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()
}
  1. Conditional Glass with .identity
.glassEffect(shouldShowGlass ? .regular : .identity)

No layout recalculation when toggling.

  1. Limit Continuous Animations Let glass rest in steady states.

  2. 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:

  1. Content layer (bottom) - No glass
  2. Navigation layer (middle) - Liquid Glass
  3. Overlay layer (top) - Vibrancy and fills on glass

4.3 Platform Differences

PlatformAdaptations
iOSFloating tab bars, bottom search placement
iPadOSFloating sidebars, ambient reflection, larger shadows
macOSConcentric window corners, adaptive search bars, taller controls
watchOSLocation-aware widgets, fluid navigation
tvOSFocused 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 = .intrinsicContentSizeUIHostingController defaults 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:

  1. Use GlassEffectContainer for multiple elements
  2. Limit continuous animations
  3. Let glass rest in steady states
  4. Test on 3-year-old devices
  5. 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:

  1. Overuse - glass everywhere
  2. Glass-on-glass stacking
  3. Content layer glass
  4. Tinting everything
  5. Breaking concentricity

Technical Anti-Patterns:

  1. Custom opacity bypassing accessibility
  2. Ignoring safe areas
  3. Hard-coded color schemes
  4. Mixing Regular and Clear variants
  5. Multiple separate glass effects without container

Usability Anti-Patterns:

  1. Busy backgrounds without dimming
  2. Insufficient contrast
  3. Excessive animations
  4. Breaking iOS conventions
  5. 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, glassEffectTransition
  • GlassEffectContainer
  • .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

ResourceApproachNotes
kube.io — "Liquid Glass in the Browser: Refraction with CSS and SVG"Physics-based 127-sample radial displacement maps derived from Snell's LawThe 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 aberrationHonest about limitations. Good middle-ground complexity.
LogRocket — "How to create Liquid Glass effects with CSS and SVG"React + Tailwind tutorial with Figma asset workflowGSAP-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

  1. 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.
  2. Browser support is Chromium-dominated. SVG filters as backdrop-filter are not reliable in Safari or Firefox — ironic given the effect's origin.
  3. Per-element displacement maps don't scale to dynamic content sizes without rebuild cost. This is a known performance ceiling for the SVG approach.
  4. 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 accessibilityReduceTransparency and accessibilityReduceMotion and 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 #available fallback pattern

Developer Blogs — Foundational:

Developer Blogs — Pattern-focused:

Web / Cross-Platform References (approximations only — not Apple APIs):

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:

  1. Reserve Liquid Glass for navigation layer only
  2. Always use GlassEffectContainer for multiple glass elements
  3. Test extensively with accessibility settings enabled
  4. Monitor performance on older devices
  5. Respect user preferences and system settings
  6. Prioritize content legibility over visual effects
  7. Use morphing transitions for smooth state changes
  8. Follow Apple's design guidelines and HIG