| name | liquid-glass-developer |
| description | Context-aware routing to iOS 26 Liquid Glass implementation patterns. Use when working with glass effects, GlassEffectContainer, morphing transitions, or iOS 26 visual effects. |
Liquid Glass Developer (iOS 26)
Purpose
Context-aware routing to iOS 26 Liquid Glass implementation patterns. Proper use of GlassEffectContainer, glassEffect modifiers, morphing transitions, and interactive effects.
When Auto-Activated
- Working with glass effects or iOS 26 visual effects
- Keywords: glass, liquid glass, glassEffect, GlassEffectContainer, iOS 26, morphing, UIGlassEffect, UIVisualEffectView, cornerConfiguration, GlassContainerViewIOS26, GlassEffectViewIOS26
- Editing files with glass effect modifiers
- Implementing navigation panels, floating buttons, or translucent UI
🚨 CRITICAL RULES (NEVER VIOLATE)
- ALWAYS group glass elements in
GlassEffectContainerIOS26 - Glass elements must be grouped for unified composition
- ALWAYS use
glassEffectIDIOS26 for morphing - Elements that appear/disappear need IDs for smooth transitions
- Glass defines its shape - Use
glassEffect(in: Shape), no separate clipShape() needed
- Glass is for navigation layer only - Never apply to content, only floating controls
- Use interactive glass for buttons - Buttons should use
.regular.interactive() for touch feedback
📋 Quick Reference
Available Utilities (View+iOS26.swift)
GlassEffectContainerIOS26(spacing: 20) {
}
.glassEffectInteractiveIOS26(in: Circle())
.glassEffectInteractiveIOS26(in: .rect(cornerRadius: 16))
.glassEffectIOS26(in: Circle())
.glassEffectIDIOS26("buttonId", in: glassNamespace)
.buttonStyleCircleGlassIOS26()
Complete Pattern Example
struct NavigationPanel: View {
@Namespace private var glassNamespace
@State private var isExpanded = false
var body: some View {
GlassEffectContainerIOS26(spacing: 20) {
HStack {
Button { } label: {
Image(systemName: "magnifyingglass")
.frame(width: 40, height: 40)
}
.glassEffectInteractiveIOS26(in: Circle())
.glassEffectIDIOS26("search", in: glassNamespace)
if isExpanded {
Button { } label: {
Image(systemName: "plus")
.frame(width: 40, height: 40)
}
.glassEffectInteractiveIOS26(in: Circle())
.glassEffectIDIOS26("add", in: glassNamespace)
}
}
}
.animation(.bouncy, value: isExpanded)
}
}
Glass Shapes
.glassEffectInteractiveIOS26(in: Circle())
.glassEffectInteractiveIOS26(in: .rect(cornerRadius: 16))
.glassEffectInteractiveIOS26(in: Capsule())
🔄 Morphing Transitions
For smooth state transitions between glass elements:
@Namespace private var glassNamespace
GlassEffectContainerIOS26 {
if editing {
plusButton
.glassEffectIDIOS26("leftButton", in: glassNamespace)
} else {
burgerButton
.glassEffectIDIOS26("leftButton", in: glassNamespace)
}
}
.animation(.bouncy, value: editing)
Key requirements:
- Elements in same
GlassEffectContainerIOS26
- Each element has
glassEffectIDIOS26 with shared namespace
- Wrap state changes with animation
⚠️ Common Mistakes
No Container Grouping
HStack {
button1.glassEffectIOS26(in: Circle())
button2.glassEffectIOS26(in: Circle())
}
GlassEffectContainerIOS26 {
HStack {
button1.glassEffectInteractiveIOS26(in: Circle())
button2.glassEffectInteractiveIOS26(in: Circle())
}
}
Redundant clipShape
.clipShape(Circle())
.glassEffectIOS26(in: Circle())
.glassEffectInteractiveIOS26(in: Circle())
Missing Morphing IDs
if isVisible {
button.glassEffectInteractiveIOS26(in: Circle())
}
if isVisible {
button
.glassEffectInteractiveIOS26(in: Circle())
.glassEffectIDIOS26("button", in: namespace)
}
Glass on Content
Text("Hello World")
.glassEffectIOS26(in: .rect(cornerRadius: 8))
Text("Hello World")
.background(Color.Background.primary)
📚 iOS Version Handling
All utilities handle iOS version checks internally:
- iOS 26+: Native glass effects applied
- iOS < 26: Fallback to
Color.Background.navigationPanel + .ultraThinMaterial
.glassEffectInteractiveIOS26(in: Circle())
if #available(iOS 26.0, *) {
self.glassEffect(.regular.interactive(), in: Circle())
} else {
self
.background(Color.Background.navigationPanel)
.background(.ultraThinMaterial)
}
🔧 UIKit Implementation
Available Utilities (UIView+iOS26Glass.swift)
let container = GlassContainerViewIOS26(spacing: 12)
container.glassContentView.addSubview(yourContent)
let glassView = GlassEffectViewIOS26()
glassView.glassContentView.addSubview(yourButton)
let config = UIButton.Configuration.glassIOS26()
let button = UIButton(configuration: config)
UIKit Pattern Example
final class NavigationBarView: UIView {
private let glassContainer = GlassContainerViewIOS26(spacing: 12)
private let buttonGlass = GlassEffectViewIOS26()
override init(frame: CGRect) {
super.init(frame: frame)
setup()
}
private func setup() {
addSubview(glassContainer) {
$0.pinToSuperview(insets: UIEdgeInsets(top: 0, left: 16, bottom: 0, right: 16))
$0.height.equal(to: 44)
}
buttonGlass.applyCircleShape(diameter: 44)
buttonGlass.layoutUsing.anchors {
$0.size(CGSize(width: 44, height: 44))
}
buttonGlass.glassContentView.addSubview(myButton) {
$0.center(in: buttonGlass.glassContentView)
}
glassContainer.glassContentView.addSubview(buttonGlass)
}
}
Shape Methods
glassView.applyCircleShape(diameter: 44)
glassView.applyCapsuleShape(height: 44)
UIKit Critical Rules
-
Always add content to glassContentView - Never add subviews directly to the glass view
glassView.addSubview(button)
glassView.glassContentView.addSubview(button)
-
Call shape methods once in setup - Not in layoutSubviews (unless height changes dynamically)
override func layoutSubviews() {
super.layoutSubviews()
glassView.applyCapsuleShape(height: bounds.height)
}
func setup() {
glassView.applyCapsuleShape(height: 44)
}
-
GlassEffectViewIOS26 is always interactive - No property to set, touch feedback is built-in
-
Use glassIOS26() for text buttons
var config = UIButton.Configuration.glassIOS26()
config.title = "Done"
config.baseForegroundColor = .Control.accent100
let button = UIButton(configuration: config)
iOS Version Handling (UIKit)
private func setupGlassEffect() {
if #available(iOS 26.0, *) {
let glassEffect = UIGlassEffect()
glassEffect.isInteractive = true
let effectView = UIVisualEffectView(effect: glassEffect)
addSubview(effectView)
glassEffectView = effectView
} else {
backgroundColor = .Background.navigationPanel
let blurView = UIVisualEffectView(effect: UIBlurEffect(style: .systemUltraThinMaterial))
addSubview(blurView)
}
}
📁 Key Files
| File | Purpose |
|---|
View+iOS26.swift | SwiftUI glass effect utilities and wrappers |
UIView+iOS26Glass.swift | UIKit glass effect utilities |
HomeBottomNavigationPanelView.swift | Navigation panel with glass buttons |
ChatInput.swift | Chat input with morphing burger/plus button |
ChatActionPanel.swift | Action buttons with interactive glass |
EditorNavigationBarView.swift | UIKit navigation bar with glass container |
EditorNavigationBarTitleView.swift | UIKit title view with capsule glass |
🔗 External Resources
✅ Implementation Checklist
SwiftUI
UIKit
Testing
🔗 Related Skills
- design-system-developer → Icons and colors used in glass buttons
- ios-dev-guidelines → SwiftUI patterns and view modifiers
Navigation: This skill covers iOS 26 Liquid Glass patterns. For implementation details, see View+iOS26.swift.