Liquid Glass in SwiftUI

Quick Reference

Modifier/ViewPurposeParameters
.glassEffect()Apply glass to viewGlass, Shape, isEnabled
GlassEffectContainerOptimize multiple glassspacing, content
.buttonStyle(.glass)Glass button styleN/A
.glassEffectID()Morphing transitionsid, namespace

Basic Implementation

Simple Glass Effect

Text("Hello")
    .padding()
    .glassEffect()  // Default: regular glass, capsule shape

Custom Shape & Tint

Image(systemName: "star")
    .glassEffect(
        .regular.tint(.blue).interactive(),
        in: .rect(cornerRadius: 12)
    )

Glass Variants

Configuration Options

// Regular glass
.glassEffect(.regular)

// With tint
.glassEffect(.regular.tint(.orange))

// Interactive (responds to touch)
.glassEffect(.regular.interactive())

// Combined
.glassEffect(.regular.tint(.blue).interactive())

Container Usage

Multiple Glass Views

GlassEffectContainer(spacing: 40) {
    HStack(spacing: 40) {
        ForEach(items) { item in
            ItemView(item)
                .glassEffect()
        }
    }
}

Union Effect

@Namespace private var namespace

GlassEffectContainer {
    HStack {
        ForEach(items.indices, id: \.self) { index in
            ItemView(items[index])
                .glassEffect()
                .glassEffectUnion(
                    id: index < 2 ? "group1" : "group2",
                    namespace: namespace
                )
        }
    }
}

Morphing Transitions

Animated Morphing

@State private var expanded = false
@Namespace private var namespace

GlassEffectContainer {
    if expanded {
        LargeView()
            .glassEffect()
            .glassEffectID("item", in: namespace)
    } else {
        SmallView()
            .glassEffect()
            .glassEffectID("item", in: namespace)
    }
}
.animation(.spring(), value: expanded)

Button Styles

Glass Buttons

// Standard glass button
Button("Action") { }
    .buttonStyle(.glass)

// Prominent glass button
Button("Important") { }
    .buttonStyle(.glassProminent)

Toolbar Integration

Glass in Toolbar

.toolbar {
    ToolbarItem(placement: .primaryAction) {
        Button("Save") { }
            .buttonStyle(.glass)
    }
}

Custom Toolbar Background

.toolbar {
    ToolbarItem(placement: .principal) {
        Text("Title")
            .sharedBackgroundVisibility(.hidden)
    }
}

Advanced Techniques

Conditional Glass

@State private var glassEnabled = true

Text("Dynamic")
    .glassEffect(isEnabled: glassEnabled)
@Namespace private var namespace

NavigationStack {
    Content()
        .toolbar {
            ToolbarItem {
                Button("Open") { }
                    .matchedTransitionSource(id: "btn", in: namespace)
            }
        }
        .sheet(isPresented: $show) {
            DetailView()
                .navigationTransition(.zoom(sourceID: "btn", in: namespace))
        }
}

Performance Tips

  1. Container Usage: Always wrap multiple glass views
  2. Spacing: Smaller = merge closer, larger = merge farther
  3. Limit Count: 5-10 glass effects maximum
  4. Disable When Hidden: Use isEnabled parameter

Common Patterns

PatternImplementation
Toggle glass.glassEffect(isEnabled: condition)
Group merge.glassEffectUnion(id:namespace:)
Custom shape.glassEffect(in: .rect(cornerRadius: 20))
State indication.tint(isActive ? .blue : .clear)

Platform Notes

  • iOS: Bottom bar placement works well
  • iPadOS: Consider larger touch targets
  • macOS: Toolbar customization expected

See Also