Liquid Glass Design System (iOS 26)
Patterns for implementing Apple's Liquid Glass — a dynamic material that blurs content behind it, reflects color and light from surrounding content, and reacts to touch and pointer interactions. Covers SwiftUI, UIKit, and WidgetKit integration.
When to Activate
- Building or updating apps for iOS 26+ with the new design language
- Implementing glass-style buttons, cards, toolbars, or containers
- Creating morphing transitions between glass elements
- Applying Liquid Glass effects to widgets
- Migrating existing blur/material effects to the new Liquid Glass API
Core Pattern — SwiftUI
Basic Glass Effect
The simplest way to add Liquid Glass to any view:
swift1Text("Hello, World!") 2 .font(.title) 3 .padding() 4 .glassEffect() // Default: regular variant, capsule shape
Customizing Shape and Tint
swift1Text("Hello, World!") 2 .font(.title) 3 .padding() 4 .glassEffect(.regular.tint(.orange).interactive(), in: .rect(cornerRadius: 16.0))
Key customization options:
.regular— standard glass effect.tint(Color)— add color tint for prominence.interactive()— react to touch and pointer interactions- Shape:
.capsule(default),.rect(cornerRadius:),.circle
Glass Button Styles
swift1Button("Click Me") { /* action */ } 2 .buttonStyle(.glass) 3 4Button("Important") { /* action */ } 5 .buttonStyle(.glassProminent)
GlassEffectContainer for Multiple Elements
Always wrap multiple glass views in a container for performance and morphing:
swift1GlassEffectContainer(spacing: 40.0) { 2 HStack(spacing: 40.0) { 3 Image(systemName: "scribble.variable") 4 .frame(width: 80.0, height: 80.0) 5 .font(.system(size: 36)) 6 .glassEffect() 7 8 Image(systemName: "eraser.fill") 9 .frame(width: 80.0, height: 80.0) 10 .font(.system(size: 36)) 11 .glassEffect() 12 } 13}
The spacing parameter controls merge distance — closer elements blend their glass shapes together.
Uniting Glass Effects
Combine multiple views into a single glass shape with glassEffectUnion:
swift1@Namespace private var namespace 2 3GlassEffectContainer(spacing: 20.0) { 4 HStack(spacing: 20.0) { 5 ForEach(symbolSet.indices, id: \.self) { item in 6 Image(systemName: symbolSet[item]) 7 .frame(width: 80.0, height: 80.0) 8 .glassEffect() 9 .glassEffectUnion(id: item < 2 ? "group1" : "group2", namespace: namespace) 10 } 11 } 12}
Morphing Transitions
Create smooth morphing when glass elements appear/disappear:
swift1@State private var isExpanded = false 2@Namespace private var namespace 3 4GlassEffectContainer(spacing: 40.0) { 5 HStack(spacing: 40.0) { 6 Image(systemName: "scribble.variable") 7 .frame(width: 80.0, height: 80.0) 8 .glassEffect() 9 .glassEffectID("pencil", in: namespace) 10 11 if isExpanded { 12 Image(systemName: "eraser.fill") 13 .frame(width: 80.0, height: 80.0) 14 .glassEffect() 15 .glassEffectID("eraser", in: namespace) 16 } 17 } 18} 19 20Button("Toggle") { 21 withAnimation { isExpanded.toggle() } 22} 23.buttonStyle(.glass)
Extending Horizontal Scrolling Under Sidebar
To allow horizontal scroll content to extend under a sidebar or inspector, ensure the ScrollView content reaches the leading/trailing edges of the container. The system automatically handles the under-sidebar scrolling behavior when the layout extends to the edges — no additional modifier is needed.
Core Pattern — UIKit
Basic UIGlassEffect
swift1let glassEffect = UIGlassEffect() 2glassEffect.tintColor = UIColor.systemBlue.withAlphaComponent(0.3) 3glassEffect.isInteractive = true 4 5let visualEffectView = UIVisualEffectView(effect: glassEffect) 6visualEffectView.translatesAutoresizingMaskIntoConstraints = false 7visualEffectView.layer.cornerRadius = 20 8visualEffectView.clipsToBounds = true 9 10view.addSubview(visualEffectView) 11NSLayoutConstraint.activate([ 12 visualEffectView.centerXAnchor.constraint(equalTo: view.centerXAnchor), 13 visualEffectView.centerYAnchor.constraint(equalTo: view.centerYAnchor), 14 visualEffectView.widthAnchor.constraint(equalToConstant: 200), 15 visualEffectView.heightAnchor.constraint(equalToConstant: 120) 16]) 17 18// Add content to contentView 19let label = UILabel() 20label.text = "Liquid Glass" 21label.translatesAutoresizingMaskIntoConstraints = false 22visualEffectView.contentView.addSubview(label) 23NSLayoutConstraint.activate([ 24 label.centerXAnchor.constraint(equalTo: visualEffectView.contentView.centerXAnchor), 25 label.centerYAnchor.constraint(equalTo: visualEffectView.contentView.centerYAnchor) 26])
UIGlassContainerEffect for Multiple Elements
swift1let containerEffect = UIGlassContainerEffect() 2containerEffect.spacing = 40.0 3 4let containerView = UIVisualEffectView(effect: containerEffect) 5 6let firstGlass = UIVisualEffectView(effect: UIGlassEffect()) 7let secondGlass = UIVisualEffectView(effect: UIGlassEffect()) 8 9containerView.contentView.addSubview(firstGlass) 10containerView.contentView.addSubview(secondGlass)
Scroll Edge Effects
swift1scrollView.topEdgeEffect.style = .automatic 2scrollView.bottomEdgeEffect.style = .hard 3scrollView.leftEdgeEffect.isHidden = true
Toolbar Glass Integration
swift1let favoriteButton = UIBarButtonItem(image: UIImage(systemName: "heart"), style: .plain, target: self, action: #selector(favoriteAction)) 2favoriteButton.hidesSharedBackground = true // Opt out of shared glass background
Core Pattern — WidgetKit
Rendering Mode Detection
swift1struct MyWidgetView: View { 2 @Environment(\.widgetRenderingMode) var renderingMode 3 4 var body: some View { 5 if renderingMode == .accented { 6 // Tinted mode: white-tinted, themed glass background 7 } else { 8 // Full color mode: standard appearance 9 } 10 } 11}
Accent Groups for Visual Hierarchy
swift1HStack { 2 VStack(alignment: .leading) { 3 Text("Title") 4 .widgetAccentable() // Accent group 5 Text("Subtitle") 6 // Primary group (default) 7 } 8 Image(systemName: "star.fill") 9 .widgetAccentable() // Accent group 10}
Image Rendering in Accented Mode
swift1Image("myImage") 2 .widgetAccentedRenderingMode(.monochrome)
Container Background
swift1VStack { /* content */ } 2 .containerBackground(for: .widget) { 3 Color.blue.opacity(0.2) 4 }
Key Design Decisions
| Decision | Rationale |
|---|---|
| GlassEffectContainer wrapping | Performance optimization, enables morphing between glass elements |
spacing parameter | Controls merge distance — fine-tune how close elements must be to blend |
@Namespace + glassEffectID | Enables smooth morphing transitions on view hierarchy changes |
interactive() modifier | Explicit opt-in for touch/pointer reactions — not all glass should respond |
| UIGlassContainerEffect in UIKit | Same container pattern as SwiftUI for consistency |
| Accented rendering mode in widgets | System applies tinted glass when user selects tinted Home Screen |
Best Practices
- Always use GlassEffectContainer when applying glass to multiple sibling views — it enables morphing and improves rendering performance
- Apply
.glassEffect()after other appearance modifiers (frame, font, padding) - Use
.interactive()only on elements that respond to user interaction (buttons, toggleable items) - Choose spacing carefully in containers to control when glass effects merge
- Use
withAnimationwhen changing view hierarchies to enable smooth morphing transitions - Test across appearances — light mode, dark mode, and accented/tinted modes
- Ensure accessibility contrast — text on glass must remain readable
Anti-Patterns to Avoid
- Using multiple standalone
.glassEffect()views without a GlassEffectContainer - Nesting too many glass effects — degrades performance and visual clarity
- Applying glass to every view — reserve for interactive elements, toolbars, and cards
- Forgetting
clipsToBounds = truein UIKit when using corner radii - Ignoring accented rendering mode in widgets — breaks tinted Home Screen appearance
- Using opaque backgrounds behind glass — defeats the translucency effect
When to Use
- Navigation bars, toolbars, and tab bars with the new iOS 26 design
- Floating action buttons and card-style containers
- Interactive controls that need visual depth and touch feedback
- Widgets that should integrate with the system's Liquid Glass appearance
- Morphing transitions between related UI states