SwiftUI Liquid Glass and Accessibility - Part 1
I started experimenting with SwiftUI to build a UI using iOS 26's new Liquid Glass design language—.glassEffect() modifiers, blur animations, refraction, and parallax. I kinda find the whole iOS glass effect too distracting after a while and wanted to make sure Reduce Motion worked properly. This is Part 1 covering Reduce Motion and Dynamic Type. Part 2 covers VoiceOver and testing.
What is Liquid Glass?
iOS 26 introduces Liquid Glass, Apple's new unified design language influenced by visionOS. It replaces the flat design from iOS 7 with rounded, translucent elements that have "optical qualities of glass" including refraction, blur, and dynamic lighting that react to motion, content, and user input.
Key visual properties: environmental refraction (refracts and reflects content behind it), dynamic light reflection (responds to light sources with realistic shading), responsive fluidity (morphs and flexes based on size and interaction), and adaptive blur (system-defined blur that adapts to background content). When glass elements morph to larger sizes, the material simulates thicker glass with deeper shadows and more pronounced lensing.
Why accessibility matters: iOS 26's Liquid Glass design is visually striking, but the blur, refraction, and parallax effects can cause accessibility issues if not handled properly. The three critical areas are Reduce Motion (disable or simplify animations), Reduce Transparency (make glass effects less translucent for better contrast), and VoiceOver (ensure glass-styled components have proper labels).
Apple built accessibility support directly into Liquid Glass. Reduce Motion decreases the intensity of glass effects, disables elastic properties, and removes parallax and refraction animations. Reduce Transparency makes Liquid Glass "frostier" and more opaque, obscuring more content behind glass elements to improve contrast. Combined settings (Reduce Transparency + Reduce Motion + Dark Mode) deliver the best visibility, performance, and battery life, making Liquid Glass behave more like iOS 25's flat design.
Reduce Motion - Disable Liquid Glass Animations
When users enable Reduce Motion, apps should disable or simplify Liquid Glass blur animations, parallax, refraction, and elastic morphing effects. Liquid Glass's dynamic refraction, parallax scrolling, and morphing animations can cause motion sickness for users with vestibular disorders.
Implementation:
struct AnimatedBadge: View {
@Environment(\.accessibilityReduceMotion) private var reduceMotion
@State private var animate = false
var body: some View {
let animation = reduceMotion
? .none
: .easeInOut(duration: 0.8).repeatForever(autoreverses: true)
Circle()
.fill(Color.blue)
.frame(width: 12, height: 12)
.scaleEffect(animate ? 1.2 : 1.0)
.onAppear {
guard !reduceMotion else { return }
withAnimation(animation) {
animate = true
}
}
}
}
The pattern is simple: Use @Environment(\.accessibilityReduceMotion) to read the system setting, set animation to .none when Reduce Motion is enabled, and early return in onAppear to prevent state changes when motion is reduced.
Using Liquid Glass with Reduce Motion:
struct GlassCard: View {
@Environment(\.accessibilityReduceMotion) private var reduceMotion
var body: some View {
VStack {
Text("Content")
}
.padding()
.background {
if reduceMotion {
// Fallback: simple blur without morphing
RoundedRectangle(cornerRadius: 16)
.fill(.ultraThinMaterial)
} else {
// Full Liquid Glass effect
RoundedRectangle(cornerRadius: 16)
.glassEffect(.regular.interactive())
}
}
}
}
When Reduce Motion is enabled, replace .glassEffect() with SwiftUI's simpler .ultraThinMaterial or .regularMaterial backgrounds. You get the blur without the dynamic morphing and refraction.
Dynamic Type - Support Scalable Text
Dynamic Type allows users to adjust text size system-wide. SwiftUI text styles (.headline, .body, .caption) scale automatically, but you need to handle layout constraints. Users with visual impairments rely on larger text sizes (up to accessibility size categories like accessibility5).
Implementation:
Text(item.name)
.font(.headline)
.fontWeight(.semibold)
.lineLimit(2)
.multilineTextAlignment(.leading)
.dynamicTypeSize(...DynamicTypeSize.accessibility5)
What matters: Use SwiftUI's built-in text styles instead of fixed point sizes. The range operator ...DynamicTypeSize.accessibility5 caps the maximum text size. Allow at least 2 lines of text to prevent truncation at larger sizes. Test layouts with Settings → Accessibility → Display & Text Size → Larger Text.
Capping Dynamic Type: Sometimes unlimited scaling breaks layouts. You can cap at a maximum size:
Text("Fixed Layout Text")
.font(.body)
.dynamicTypeSize(.medium...DynamicTypeSize.xxxLarge)
This allows scaling up to xxxLarge but prevents accessibility sizes that might break the design.
Continue to Part 2 for VoiceOver support and testing strategies.