swiftui-liquid-glass
SwiftUI Liquid Glass provides APIs for implementing the dynamic translucent material effect introduced in iOS 26 and across Apple platforms. Use this skill when building custom views with glass-morphic backgrounds, interactive glass buttons, glass containers, morphing transitions, or adopting iOS 26 design patterns that require blur, vibrancy, tinting, and touch reactivity beyond standard framework components.
git clone --depth 1 https://github.com/dpearson2699/swift-ios-skills /tmp/swiftui-liquid-glass && cp -r /tmp/swiftui-liquid-glass/skills/swiftui-liquid-glass ~/.claude/skills/swiftui-liquid-glassSKILL.md
# SwiftUI Liquid Glass
Liquid Glass is the dynamic translucent material introduced in iOS 26 (and iPadOS 26,
macOS 26, tvOS 26, watchOS 26). It blurs content behind it, reflects surrounding color
and light, and reacts to touch and pointer interactions. Standard SwiftUI components
(tab bars, toolbars, navigation bars, sheets) adopt Liquid Glass automatically when
built with the iOS 26 SDK. Use the APIs below for custom views and controls.
See [references/liquid-glass.md](references/liquid-glass.md) for the full API reference with additional examples.
## Contents
- [Workflow](#workflow)
- [Core API Summary](#core-api-summary)
- [Code Examples](#code-examples)
- [Common Mistakes](#common-mistakes)
- [Review Checklist](#review-checklist)
- [References](#references)
## Workflow
Choose the path that matches the request:
### 1. Implement a new feature with Liquid Glass
1. Identify target surfaces (cards, chips, floating controls, custom bars).
2. Decide shape, prominence, and whether each element needs interactivity.
3. Wrap grouped glass elements in a `GlassEffectContainer`.
4. Apply `.glassEffect()` **after** layout and appearance modifiers.
5. Add `.interactive()` only to tappable/focusable elements.
6. Add morphing transitions with `glassEffectID(_:in:)` where the view hierarchy
changes with animation.
7. Gate with `if #available(iOS 26, *)` and provide a fallback for earlier versions.
### 2. Improve an existing feature with Liquid Glass
1. Find custom blur/material backgrounds that can be replaced with `.glassEffect()`.
2. Wrap sibling glass elements in `GlassEffectContainer` for blending and performance.
3. Replace custom glass-like buttons with `.buttonStyle(.glass)` or `.buttonStyle(.glassProminent)`.
4. Add morphing transitions where animated insertion/removal occurs.
### 3. Review existing Liquid Glass usage
Run through the Review Checklist below and verify each item.
## Core API Summary
### glassEffect(_:in:)
Applies Liquid Glass behind a view. Default: `.regular` variant in a `Capsule` shape.
```swift
nonisolated func glassEffect(
_ glass: Glass = .regular,
in shape: some Shape = DefaultGlassEffectShape()
) -> some View
```
### Glass struct
| Property / Method | Purpose |
|---|---|
| `.regular` | Standard glass material |
| `.clear` | Clear variant (minimal tint) |
| `.identity` | No visual effect (pass-through) |
| `.tint(_:)` | Add a color tint for prominence |
| `.interactive(_:)` | React to touch and pointer interactions |
Chain them: `.regular.tint(.blue).interactive()`
### GlassEffectContainer
Wraps multiple glass views for shared rendering, blending, and morphing.
```swift
GlassEffectContainer(spacing: 24) {
// child views with .glassEffect()
}
```
The `spacing` controls when nearby glass shapes begin to blend. Match or exceed
the interior layout spacing so shapes merge during animated transitions but remain
separate at rest.
### Morphing & Transitions
| Modifier | Purpose |
|---|---|
| `glassEffectID(_:in:)` | Stable identity for morphing during view hierarchy changes |
| `glassEffectUnion(id:namespace:)` | Merge multiple views into one glass shape |
| `glassEffectTransition(_:)` | Control how glass appears/disappears |
Transition types: `.matchedGeometry` (default when within spacing), `.materialize`
(fade content + animate glass in/out), `.identity` (no transition).
### Button Styles
```swift
Button("Action") { }
.buttonStyle(.glass) // standard glass button
Button("Primary") { }
.buttonStyle(.glassProminent) // prominent glass button
```
### Scroll Edge Effects and Background Extension (iOS 26+)
These complement Liquid Glass when building custom toolbars and scroll views:
```swift
ScrollView {
content
}
.scrollEdgeEffectStyle(.soft, for: .top) // Configures edge effect at scroll boundaries
// Duplicate view into mirrored copies at safe area edges with blur (e.g., under sidebars)
content
.backgroundExtensionEffect()
```
### ToolbarSpacer (iOS 26+)
Creates a visual break between items in toolbars:
```swift
.toolbar {
ToolbarItem { Button("Edit") { } }
ToolbarSpacer(.fixed)
ToolbarItem { Button("Share") { } }
}
```
## Code Examples
### Basic glass effect with availability gate
```swift
if #available(iOS 26, *) {
Text("Status")
.padding()
.glassEffect(.regular.interactive(), in: .rect(cornerRadius: 16))
} else {
Text("Status")
.padding()
.background(.ultraThinMaterial, in: RoundedRectangle(cornerRadius: 16))
}
```
### Grouped glass elements in a container
```swift
GlassEffectContainer(spacing: 24) {
HStack(spacing: 24) {
ForEach(tools) { tool in
Image(systemName: tool.icon)
.frame(width: 56, height: 56)
.glassEffect(.regular.interactive())
}
}
}
```
### Morphing transition
```swift
@State private var isExpanded = false
@Namespace private var ns
var body: some View {
GlassEffectContainer(spacing: 40) {
HStack(spacing: 40) {
Image(systemName: "pencil")
.frame(width: 80, height: 80)
.glassEffect()
.glassEffectID("pencil", in: ns)
if isExpanded {
Image(systemName: "eraser.fill")
.frame(width: 80, height: 80)
.glassEffect()
.glassEffectID("eraser", in: ns)
}
}
}
Button("Toggle") {
withAnimation { isExpanded.toggle() }
}
.buttonStyle(.glass)
}
```
### Unioning views into a single glass shape
```swift
@Namespace private var ns
GlassEffectContainer(spacing: 20) {
HStack(spacing: 20) {
ForEach(items.indices, id: \.self) { i in
Image(systemName: items[i])
.frame(width: 80, height: 80)
.glassEffect()
.glassEffectUnion(id: i < 2 ? "group1" : "group2", namespace: ns)
}
}
}
```
### Tinted glass baDiscover and configure Bluetooth and Wi-Fi accessories using AccessorySetupKit. Use when presenting a privacy-preserving accessory picker, defining discovery descriptors for BLE or Wi-Fi devices, handling accessory session events, migrating from CoreBluetooth permission-based scanning, or setting up accessories without requiring broad Bluetooth permissions.
Implement, review, or improve Live Activities and Dynamic Island experiences in iOS apps using ActivityKit. Use when building real-time updating widgets for the Lock Screen and Dynamic Island — delivery tracking, sports scores, ride-sharing status, workout timers, media playback, or any time-sensitive information that updates in real time. Also use when working with ActivityKit, ActivityAttributes, Activity lifecycle (request/update/end), Dynamic Island layouts (compact/minimal/expanded), push-to-update Live Activities, or Lock Screen live widgets.
Measure ad effectiveness with privacy-preserving attribution using AdAttributionKit. Use when registering ad impressions, handling attribution postbacks, updating conversion values, implementing re-engagement attribution, configuring publisher or advertiser apps, or replacing SKAdNetwork with AdAttributionKit for ad measurement.
Implement AlarmKit alarms and countdown timers for iOS and iPadOS with Lock Screen, Dynamic Island, StandBy, and paired Apple Watch system UI. Covers AlarmManager scheduling, AlarmAttributes and AlarmPresentation, AlarmButton stop and snooze actions, authorization, state observation, countdown widget-extension handoff, and Live Activity integration. Use when building wake-up alarms, countdown timers, or alarm-style alerts that need Apple's system alarm experience.
Build iOS App Clips with invocation URLs, App Clip Codes, NFC, QR codes, Safari banners, Maps, Messages, target setup, App Store Connect experiences, size/capability constraints, NSUserActivity routing, SKOverlay promotion, App Group/keychain handoff, ephemeral notifications, location confirmation, and full-app migration. Use when creating App Clips or wiring App Clip invocation, experience configuration, or full-app handoff.
Implement App Intents for Siri, Shortcuts, Spotlight, widgets, Control Center, and Apple Intelligence on iOS. Covers AppIntent actions, AppEntity and EntityQuery models, AppShortcutsProvider phrases, IndexedEntity Spotlight indexing, WidgetConfigurationIntent, SnippetIntent, and assistant schemas. Use when exposing app actions or entities to system surfaces.
Optimize App Store product pages for search visibility and conversion. Use for App Store Optimization (ASO), keyword research, app name/subtitle/keyword-field strategy, conversion-focused descriptions and promotional text, screenshot captions and ordering, Custom Product Pages with assigned search keywords, In-App Events, Product Page Optimization tests, localized metadata, ratings/review strategy, and in-app review prompt timing with RequestReviewAction or AppStore.requestReview. Also use when routing ASO vs App Store review, privacy/ATT, or StoreKit implementation boundaries.
Prepare for App Store review and prevent rejections. Covers App Store review guidelines, app rejection reasons, PrivacyInfo.xcprivacy privacy manifest requirements, required API reason codes, in-app purchase IAP and StoreKit rules, App Store Guidelines compliance, ATT App Tracking Transparency, EU DMA Digital Markets Act, HIG compliance checklist, app submission preparation, review preparation, metadata requirements, entitlements, widgets, and Live Activities review rules. Use when preparing for App Store submission, fixing rejection reasons, auditing privacy manifests, implementing ATT consent flow, configuring StoreKit IAP, or checking HIG compliance.