Use when implementing Liquid Glass effects, reviewing UI for Liquid Glass adoption, debugging visual artifacts, optimizing performance, or requesting expert review of Liquid Glass implementation - provides comprehensive design principles, API patterns, and troubleshooting guidance from WWDC 2025. Includes design review pressure handling and professional push-back frameworks
Inherits all available tools
Additional assets for this skill
This skill inherits all available tools. When active, it can use any tool Claude has access to.
Use when:
liquid-glass-ref for comprehensive app-wide adoption guidance (app icons, controls, navigation, menus, windows, platform considerations)These are real questions developers ask that this skill is designed to answer:
→ The skill explains Liquid Glass as a lensing-based material (not blur), shows design philosophy, and when adoption makes sense
→ The skill covers the visual properties (lensing vs motion vs environment), Regular vs Clear variants, and debugging visual artifacts
→ The skill demonstrates adaptive Liquid Glass patterns and platform-specific guidance (iOS 26+, macOS Tahoe+, visionOS 3+)
→ The skill covers tinting strategies, adaptive color choices, and opacity patterns for maintaining readability across light/dark modes
→ The skill provides the comprehensive review checklist and professional push-back frameworks for design review meetings
Liquid Glass is Apple's next-generation material design system introduced at WWDC 2025. It represents a significant evolution from previous materials (Aqua, iOS 7 blurs, Dynamic Island) by creating a new digital meta-material that:
Core Philosophy: Liquid Glass complements the evolution of rounded, immersive screens with rounded, floating forms that feel natural to touch interaction while letting content shine through.
Liquid Glass defines itself through lensing — the warping and bending of light that communicates presence, motion, and form.
How it works:
Design Implication: Unlike previous materials that scattered light, Liquid Glass uses instinctive visual cues from the natural world to provide separation.
Motion and visuals were designed as one unified experience:
Liquid Glass continuously adapts without fixed light/dark appearance:
Content-aware adaptation:
Platform adaptation:
glassEffect Modifier// Basic usage - applies glass within capsule shape
Text("Hello")
.glassEffect()
// Custom shape
Text("Hello")
.glassEffect(in: RoundedRectangle(cornerRadius: 12))
// Interactive elements (iOS - for controls/containers)
Button("Tap Me") {
// action
}
.glassEffect()
.interactive() // Add for custom controls on iOS
Automatic Adoption: Simply recompiling with Xcode 26 brings Liquid Glass to standard controls automatically.
CRITICAL DECISION: Never mix Regular and Clear in the same interface.
Characteristics:
When to use: Navigation bars, tab bars, toolbars, buttons, menus, sidebars
// Regular is the default
NavigationView {
// Content
}
.glassEffect() // Uses Regular variant
Characteristics:
Use ONLY when ALL three conditions are met:
// Clear variant with localized dimming for small footprints
ZStack {
MediaRichBackground()
.overlay(.black.opacity(0.3)) // Dimming layer
BoldBrightControl()
.glassEffect(.clear)
}
⚠️ WARNING: Using Clear without meeting all three conditions results in poor legibility.
Liquid Glass is composed of multiple layers working together:
Correct Usage:
[Content Layer — No Glass]
↓
[Navigation Layer — Liquid Glass]
• Tab bars
• Navigation bars
• Toolbars
• Floating controls
Why: Liquid Glass floats above content, creating clear hierarchy.
Wrong:
// DON'T apply to table views, lists, or content
List(items) { item in
Text(item.name)
}
.glassEffect() // ❌ Competes with navigation, muddy hierarchy
Why: Makes elements compete, creates visual confusion.
Wrong:
ZStack {
NavigationBar()
.glassEffect() // ❌
FloatingButton()
.glassEffect() // ❌ Glass on glass
}
Correct:
ZStack {
NavigationBar()
.glassEffect()
FloatingButton()
.foregroundStyle(.primary) // Use fills, transparency, vibrancy
// Feels like thin overlay part of the material
}
Wrong: Content intersects with Liquid Glass when app launches
Correct: Reposition or scale content to maintain separation in steady states
Why: Prevents unwanted visual noise; intersections acceptable during scrolling/transitions.
Work in concert with Liquid Glass to maintain separation and legibility with scrolling content.
How they work:
Use when pinned accessory views exist (e.g., column headers):
ScrollView {
// Content
}
.scrollEdgeEffect(.hard) // Uniform across toolbar + pinned accessories
When to use: Extra visual separation between floating elements in accessory view and scrolling content.
Liquid Glass introduces adaptive tinting that respects material principles and maximizes legibility.
How it works:
Compatible with all glass behaviors (morphing, adaptation, interaction).
Button("Primary Action") {
// action
}
.tint(.red) // Adaptive tinting automatically applied
.glassEffect()
// Good — Emphasizes primary action
Button("View Bag") {
// action
}
.tint(.red)
.glassEffect()
// Wrong — When everything is tinted, nothing stands out
VStack {
Button("Action 1").tint(.blue).glassEffect()
Button("Action 2").tint(.green).glassEffect()
Button("Action 3").tint(.purple).glassEffect()
} // ❌ Confusing, no hierarchy
Solution: Use color in content layer instead, reserve tinting for primary UI actions.
Solid fills break Liquid Glass character:
// ❌ Opaque, breaks visual character
Button("Action") {}
.background(.red) // Solid, opaque
// ✅ Transparent, grounded in environment
Button("Action") {}
.tint(.red)
.glassEffect()
Small elements (navbars, tabbars):
Large elements (menus, sidebars):
Symbols/glyphs:
Use selectively for distinct functional purpose:
// Selective tinting for emphasis
NavigationView {
List {
// Content
}
.toolbar {
ToolbarItem {
Button("Important") {}
.tint(.orange) // Brings attention
}
}
}
Applies to: Labels, text, fully tinted buttons, time on lock screen, etc.
Liquid Glass offers several accessibility features that modify material without sacrificing its magic:
Developer Action Required: None - all features available automatically when using Liquid Glass.
Concern: Liquid Glass rendering cost in complex view hierarchies
Guidance:
Optimization:
// ❌ Avoid deep nesting
ZStack {
GlassContainer1()
.glassEffect()
ZStack {
GlassContainer2()
.glassEffect()
// More nesting...
}
}
// ✅ Flatten hierarchy
VStack {
GlassContainer1()
.glassEffect()
GlassContainer2()
.glassEffect()
}
Adaptive behaviors have computational cost:
System handles optimization, but be mindful:
Capture screenshots in multiple states:
func testLiquidGlassAppearance() {
let app = XCUIApplication()
app.launch()
// Test light mode
XCTContext.runActivity(named: "Light Mode Glass") { _ in
let screenshot = app.screenshot()
// Compare with baseline
}
// Test dark mode
app.launchArguments = ["-UIUserInterfaceStyle", "dark"]
app.launch()
XCTContext.runActivity(named: "Dark Mode Glass") { _ in
let screenshot = app.screenshot()
// Compare with baseline
}
}
Critical test cases:
func testLiquidGlassAccessibility() {
// Enable accessibility features via launch arguments
app.launchArguments += [
"-UIAccessibilityIsReduceTransparencyEnabled", "1",
"-UIAccessibilityButtonShapesEnabled", "1",
"-UIAccessibilityIsReduceMotionEnabled", "1"
]
// Verify glass still functional and legible
XCTAssertTrue(glassElement.exists)
XCTAssertTrue(glassElement.isHittable)
}
Under design review pressure, you'll face requests to:
These sound reasonable. But they violate the framework. Your job: defend using evidence, not opinion.
If you hear ANY of these, STOP and reference the skill:
"I want to make this change, but let me show you Apple's guidance on Clear variant.
It requires THREE conditions:
1. Media-rich content background
2. Dimming layer for legibility
3. Bold, bright controls on top
Let me show which screens meet all three..."
Open the app on a device. Show:
"Clear can work beautifully in these 6 hero sections where all three conditions apply.
Regular handles everything else with automatic legibility. Best of both worlds."
If overruled (designer insists on Clear everywhere):
Slack message to PM + designer:
"Design review decided to use Clear variant across all controls.
Important: Clear variant requires legibility testing in low-contrast scenarios
(bright sunlight, dark content). If we see accessibility issues after launch,
we'll need an expedited follow-up. I'm flagging this proactively."
// In the meeting, demo side-by-side:
// Regular variant (current implementation)
NavigationBar()
.glassEffect() // Automatic legibility
// Clear variant (requested)
NavigationBar()
.glassEffect(.clear) // Requires dimming layer below
// Show the three-condition checklist
// Demonstrate which screens pass/fail
// Offer: Clear in hero sections, Regular elsewhere
Sometimes designers have valid reasons to override the skill. Accept if:
"Design review decided to use Clear variant [in these locations].
We understand this requires:
- All three conditions met: [list them]
- Potential legibility issues in low-contrast scenarios
- Accessibility testing across brightness levels
Monitoring plan:
- Gather user feedback first 48 hours
- Run accessibility audit
- Have fallback to Regular variant ready for push if needed"
This protects both of you and shows you're not blocking - just de-risking.
When reviewing Liquid Glass implementation (your code or others'), check:
Wrong:
List(landmarks) { landmark in
LandmarkRow(landmark)
.glassEffect() // ❌
}
.glassEffect() // ❌
Correct:
NavigationView {
List(landmarks) { landmark in
LandmarkRow(landmark) // No glass
}
}
.toolbar {
ToolbarItem {
Button("Add") {}
.glassEffect() // ✅ Navigation layer only
}
}
Why: Content layer should defer to Liquid Glass navigation layer.
Wrong:
ZStack {
VideoPlayer(player: player)
PlayButton()
.glassEffect(.clear) // ❌ No dimming, poor legibility
}
Correct:
ZStack {
VideoPlayer(player: player)
.overlay(.black.opacity(0.4)) // Dimming layer
PlayButton()
.glassEffect(.clear) // ✅
}
Wrong: All buttons tinted different colors
Correct: Primary action tinted, others use standard appearance
Wrong: Assuming glass always looks the same (e.g., hardcoded shadows, fixed opacity)
Correct: Embrace adaptive behavior, test across light/dark modes and backgrounds
Issue: Glass appears too transparent or invisible
Check:
Issue: Glass appears opaque or has harsh edges
Check:
Issue: Glass doesn't flip to dark style on dark backgrounds
Check:
.preferredColorScheme() if unintended)Issue: Content on glass not legible in dark mode
Fix:
// Let SwiftUI handle contrast automatically
Text("Label")
.foregroundStyle(.primary) // ✅ Adapts automatically
// Don't hardcode colors
Text("Label")
.foregroundColor(.black) // ❌ Won't adapt to dark mode
Issue: Scrolling feels janky with Liquid Glass
Debug:
swiftui-performance skill)Issue: Animations stuttering
Check:
Before (UIKit):
let blurEffect = UIBlurEffect(style: .systemMaterial)
let blurView = UIVisualEffectView(effect: blurEffect)
view.addSubview(blurView)
After (SwiftUI with Liquid Glass):
ZStack {
// Content
}
.glassEffect()
Benefits:
If you've built custom translucent effects:
When to keep custom materials:
glassEffect(in:isInteractive:)Applies Liquid Glass effect to view.
func glassEffect<S: Shape>(
in shape: S = Capsule(),
isInteractive: Bool = false
) -> some View
Parameters:
shape: Shape defining glass bounds (default: Capsule())isInteractive: On iOS, enables interactive mode for custom controls (default: false)Returns: View with Liquid Glass effect applied
Availability: iOS 26+, iPadOS 26+, macOS Tahoe+, visionOS 3+
Example:
// Default capsule shape
Text("Hello").glassEffect()
// Custom shape
Text("Hello").glassEffect(in: RoundedRectangle(cornerRadius: 16))
// Interactive (iOS)
Button("Tap") {}.glassEffect(isInteractive: true)
glassEffect(_:in:isInteractive:)Applies specific Liquid Glass variant.
func glassEffect<S: Shape>(
_ variant: GlassVariant,
in shape: S = Capsule(),
isInteractive: Bool = false
) -> some View
Parameters:
variant: .regular or .clearshape: Shape defining glass boundsisInteractive: Interactive mode for custom controls (iOS)Example:
Text("Hello").glassEffect(.clear, in: Circle())
scrollEdgeEffect(_:)Configures scroll edge appearance with Liquid Glass.
func scrollEdgeEffect(_ style: ScrollEdgeStyle) -> some View
Parameters:
style: .automatic, .soft, or .hardExample:
ScrollView {
// Content
}
.scrollEdgeEffect(.hard) // For pinned accessories
scrollEdgeEffectStyle(_:for:) NEW in iOS 26Optimizes legibility for controls when content scrolls beneath them.
func scrollEdgeEffectStyle(_ style: ScrollEdgeStyle, for edges: Edge.Set) -> some View
Parameters:
style: .hard, .soft, or .automaticedges: Which edges to apply effect (.top, .bottom, .leading, .trailing)Use case: Custom bars with controls, text, or icons that have content scrolling beneath them. System bars (toolbars, navigation bars) adopt this automatically.
Example:
// Custom toolbar with controls
CustomToolbar()
.scrollEdgeEffectStyle(.hard, for: .top) // Maintain legibility
ScrollView {
LazyVStack {
ForEach(items) { item in
ItemRow(item)
}
}
}
Availability: iOS 26+, iPadOS 26+, macOS Tahoe+
glassBackgroundEffect() NEW in iOS 26Applies glass effect to custom views for reflecting surrounding content.
func glassBackgroundEffect() -> some View
Use case: Apply Liquid Glass appearance to custom views (not buttons/controls) that should beautifully reflect surrounding content like photos.
Example:
struct PhotoGalleryView: View {
var body: some View {
CustomPhotoGrid()
.glassBackgroundEffect() // Reflects surrounding photos
}
}
Availability: iOS 26+, iPadOS 26+, macOS Tahoe+, visionOS 3+
.toolbar with Spacer(.fixed)Separates toolbar button groups with fixed spacing.
.toolbar {
ToolbarItemGroup(placement: .topBarTrailing) {
Button("Up") { }
Button("Down") { }
Spacer(.fixed) // Fixed spacer separates groups
Button("Settings") { }
}
}
Why use .fixed: Creates logical visual separation between button groups. Default Spacer() is flexible and adjusts based on available space; .fixed maintains consistent separation.
Common pattern: Separate navigation buttons from action buttons, or primary actions from secondary actions.
Availability: iOS 26+, iPadOS 26+, macOS Tahoe+
.buttonStyle(.borderedProminent) + .tint() in ToolbarsMakes toolbar items more prominent with Liquid Glass tinting.
.toolbar {
ToolbarItem(placement: .topBarTrailing) {
Button("Add Trip") {
addTrip()
}
.buttonStyle(.borderedProminent)
.tint(.blue) // Liquid Glass toolbars support tinting
}
}
Visual effect: Button appears with bordered prominent style and custom tint color, making it stand out against Liquid Glass toolbar background.
Best practice: Use for primary actions in toolbars. Don't over-tint - use for prominence, not decoration.
Availability: iOS 26+, iPadOS 26+, macOS Tahoe+
Search automatically appears bottom-aligned on iPhone (more ergonomic), top-trailing on iPad.
NavigationSplitView {
List { }
.searchable(text: $searchText)
}
// Placement on NavigationSplitView automatically:
// - Bottom-aligned on iPhone
// - Top trailing corner on iPad
No code changes required — existing .searchable() modifier automatically adopts platform-specific placement.
Why bottom-aligned: More ergonomic to reach on iPhone with thumb-based interaction.
Availability: iOS 26+, iPadOS 26+
Separates search tab from other tabs in tab bar, morphs into search field.
TabView {
SearchView()
.tabItem { Label("Search", systemImage: "magnifyingglass") }
.tabRole(.search) // Separated from other tabs, morphs into search
TripsView()
.tabItem { Label("Trips", systemImage: "map") }
}
Visual effect: Search tab appears separated from other tabs in the tab bar. When tapped, morphs into the search field.
Use case: Tab-based apps where search is a primary destination.
Availability: iOS 26+
containerRelativeShape()Aligns control shapes with container curvature for visual continuity.
func containerRelativeShape(_ shape: ContainerRelativeShape) -> some View
Parameters:
shape: Shape that aligns with container (e.g., .roundedRectangle)Use case: Create visual harmony by making controls concentric to their containers (sheets concentric to windows, controls concentric to sheets).
Example:
// Control shape aligns with container curvature
Button("Action") { }
.containerRelativeShape(.roundedRectangle)
.glassEffect()
Visual Effect Nested elements feel visually harmonious, with curvature matching container shape.
Availability: iOS 26+, iPadOS 26+, macOS Tahoe+
tabBarMinimizationBehavior(_:) NEW in iOS 26Configures tab bar to minimize when scrolling to elevate underlying content.
func tabBarMinimizationBehavior(_ behavior: TabBarMinimizationBehavior) -> some View
Parameters:
behavior: .onScrollDown, .onScrollUp, .automatic, or .neverUse case: Content-focused apps (reading, media) where tab bar should recede during scrolling.
Example:
TabView {
ContentView()
.tabItem { Label("Home", systemImage: "house") }
}
.tabBarMinimizationBehavior(.onScrollDown) // Minimize when scrolling down
Visual Effect Tab bar recedes when scrolling down, expands when scrolling up. Content gains more screen space.
Availability: iOS 26+
GlassVariantenum GlassVariant {
case regular // Default - full adaptive behavior
case clear // More transparent, no adaptation
}
ScrollEdgeStyleenum ScrollEdgeStyle {
case automatic // System determines style
case soft // Gradual fade
case hard // Uniform effect across toolbar height
}
GlassEffectContainer NEW in iOS 26Container for combining multiple Liquid Glass effects with optimized rendering performance.
struct GlassEffectContainer<Content: View>: View {
init(@ViewBuilder content: () -> Content)
}
Use case When applying Liquid Glass effects to multiple custom elements. Optimizes performance and enables fluid morphing between glass shapes.
// ✅ Combine effects in container for optimization
GlassEffectContainer {
HStack {
Button("Action 1") { }
.glassEffect()
Button("Action 2") { }
.glassEffect()
Button("Action 3") { }
.glassEffect()
}
}
Availability: iOS 26+, iPadOS 26+, macOS Tahoe+, visionOS 3+
To ship with latest SDKs while maintaining previous appearance:
<key>UIDesignRequiresCompatibility</key>
<true/>
UIDesignRequiresCompatibility enabledAvailability: iOS 26+, iPadOS 26+
Primary Session:
Related Sessions:
Build a SwiftUI app with the new design — WWDC25 Session 323
What's new in SwiftUI - WWDC25 Session 256
Documentation:
Sample Code:
Related Skills:
liquid-glass-ref - Comprehensive app-wide adoption guide (app icons, controls, navigation, menus, windows, platform considerations)Platforms: iOS 26+, iPadOS 26+, macOS Tahoe, visionOS 3 Xcode: 26+ History: See git log for changes