Scale Liquid Glass UI with Tokens and One SwiftUI Modifier
Centralize Liquid Glass in iOS 26 apps using design tokens (e.g., card radius 28, stroke width 1), a single .glassSurface modifier with iOS 26 glassEffect fallback to ultraThinMaterial, and components like GlassCard for consistent, accessible glassy UIs that morph cohesively.
Design Tokens Ensure UI Cohesion Across Components
Define tokens in GlassTokens.swift to enforce consistency: Radius.card = 28, pill = 999 (Capsule), sheet = 34; Padding.card = EdgeInsets(16,16,16,16), pill = (10,14,10,14); Stroke.width = 1, subtleOpacity = 0.22, strong = 0.35; Shadow.radius = 18, y=8, opacity=0.18. Introduce three glass levels—chrome (toolbars), surface (cards), element (buttons)—to standardize behavior. These prevent drift from manual tweaks, turning ad-hoc glassy effects into a scalable system that feels designed, not random.
Tokens feed the .glassSurface<S: Shape>(level, in shape) extension, applying padding by level (e.g., chrome: (10,12,10,12)), white stroke (opacity varies by level), and soft shadow. Background uses #available(iOS 26.0,*) ? shape.fill(Color.clear).glassEffect(in: shape) : shape.fill(.ultraThinMaterial), always honoring @Environment(\ .accessibilityReduceTransparency) with Color(.secondarySystemBackground) fallback. Avoid mixing legacy Material on iOS 26—Apple positions Liquid Glass as a distinct system material.
Single Modifier Powers Reusable Components
The GlassSurfaceModifier wraps content in consistent layers: padding → backgroundLayer → strokeBorder → shadow. Components leverage it simply:
- GlassCard: content.glassCard(.surface) with RoundedRectangle(cornerRadius: 28, style: .continuous). Usage: GlassCard { VStack { Text("Today").font(.headline); Text("6,842 steps").foregroundStyle(.secondary) } }—semantic text styles ensure legibility without translucency reliance.
- GlassIconButton: Button with Image(systemName:), frame(44x44), .buttonStyle(.plain).glassSurface(.element, in: Circle()).contentShape(Circle())—plain style prevents default button fights with glass material.
- GlassToolbarBackground: safeAreaInset(edge: .top) with HStack(title, Spacer, GlassIconButton), .glassSurface(.chrome, in: RoundedRectangle(cornerRadius: 22)).padding(horizontal:16, top/bottom:10). Makes apps feel iOS 26-native instantly.
This shifts mindset: select level/shape per use case, not recreate effects.
Morphing and Usability Rules for Production
For connected glass, wrap in GlassEffectContainer { } with .glassEffectID(id: "search", in: namespace) on morphing elements (e.g., Button → TextField). Animate with .animation(.snappy, value: expanded)—enables iOS 26 shapes to flow as one material, gated behind availability.
Usability rules counter legibility critiques (addressed by iOS 26 tint/opacity settings):
- Semantic text: .foregroundStyle(.primary/.secondary), never Color.white.opacity(0.8).
- Always check Reduce Transparency—wired into modifier to avoid contrast bugs.
- Restrain use: .chrome for toolbars/floats, .surface for cards—glass structures, doesn't decorate everything.
Full screen: ZStack gradient background + ScrollView of GlassCards (e.g., "Weekly Summary", HRV 42ms, Sleep 7h18m) + .glassToolbar(). Rich backgrounds amplify refraction; system handles user-tuned translucency.
Result: Ship iOS 26-native feel with restraint—demo to product via tokens, one modifier, morphing-ready components. GitHub: https://github.com/sanjaynela/liquid-glass-ios-system.