Implementing Liquid Glass Design in Widgets
Overview
Liquid Glass is a dynamic, adaptive material introduced in iOS 26 across Apple platforms that combines the optical properties of glass with a sense of fluidity. When applied to widgets, Liquid Glass creates a modern, cohesive look that integrates seamlessly with the system UI. This guide covers how to implement and optimize Liquid Glass effects in widgets, including handling different rendering modes, configuring appearance, and ensuring compatibility across platforms. You should always seek guides on Liquid Glass when asked for help adopting new Apple design.
Understanding Widget Rendering Modes
Widgets can appear in two primary rendering modes when using Liquid Glass:
Full Color Mode
- Default rendering mode
- Displays all colors, images, and transparency as designed
- Used when widgets appear on standard backgrounds
Accented Mode
- Used when a person chooses a tinted or clear appearance for their Home Screen
- Primary and accented content is tinted white (iOS and macOS)
- Opaque images are tinted with a single white color
- Transparent content and gradients maintain opacity but are tinted white
- Background is replaced with themed glass or tinted color effect
Supporting Liquid Glass in Widgets
To update your widget to support Liquid Glass:
- Add the
widgetRenderingModeenvironment variable to detect the current rendering mode:
struct MyWidgetView: View {
@Environment(\.widgetRenderingMode) var renderingMode
var body: some View {
if renderingMode == .accented {
// Layout optimized for accented mode
} else {
// Standard full-color layout
}
}
}- Group your views into primary and accent groups using the
widgetAccentable(_:)modifier:
HStack(alignment: .center, spacing: 0) {
VStack(alignment: .leading) {
Text("Widget Title")
.font(.headline)
.widgetAccentable() // This will be in the accent group
Text("Widget Subtitle")
// This text is in the primary group by default
}
Image(systemName: "star.fill")
.widgetAccentable() // This will be in the accent group
}- Configure image rendering using the
WidgetAccentedRenderingModemodifier:
Image("myImage")
.widgetAccentedRenderingMode(.monochrome) // Will be rendered as monochrome in accented mode- Follow these best practices for Liquid Glass compatibility:
- Display full-color images only in the
fullColorrendering mode - Adjust layouts as needed for the
accentedrendering mode - Use the
widgetAccentable(_:)modifier strategically to create visual hierarchy
- Display full-color images only in the
Container Backgrounds for Widgets
Properly configuring container backgrounds is essential for Liquid Glass effects:
var body: some View {
VStack {
// Widget content here
}
.containerBackground(for: .widget) {
Color.blue.opacity(0.2) // Custom background color
}
}When a person chooses a tinted or clear appearance, the system:
- Removes the background
- Replaces it with a themed glass or tinted color effect
Optimizing Widget Appearance
Background Removal
By default, the system removes widget backgrounds in certain contexts. To explicitly opt out:
var body: some WidgetConfiguration {
StaticConfiguration(kind: "MyWidget", provider: Provider()) { entry in
MyWidgetView(entry: entry)
}
.containerBackgroundRemovable(false) // Prevents background removal
}Important: Marking a background as non-removable excludes your widget from contexts that require removable backgrounds (iPad Lock Screen, StandBy).
Widget Textures in visionOS
For visionOS, you can specify the widget texture:
var body: some WidgetConfiguration {
StaticConfiguration(kind: "MyWidget", provider: Provider()) { entry in
MyWidgetView(entry: entry)
}
.widgetTexture(.glass) // Default is glass
}Available textures include:
.glass- Default texture with glass-like appearance.paper- Paper-like texture
Mounting Styles for Widgets
In visionOS, widgets can be mounted in different styles:
var body: some WidgetConfiguration {
StaticConfiguration(kind: "MyWidget", provider: Provider()) { entry in
MyWidgetView(entry: entry)
}
.supportedMountingStyles([.recessed, .elevated])
}Available mounting styles:
.recessed- Widget appears embedded into a vertical surface.elevated- Widget appears on top of a surface (default for horizontal surfaces)
Implementing Liquid Glass Effects in Custom Widget Elements
For custom elements within widgets that need Liquid Glass effects:
Text("Custom Element")
.padding()
.glassEffect() // Applies default Liquid Glass effect (capsule shape)
Image(systemName: "star.fill")
.frame(width: 60, height: 60)
.glassEffect(.regular, in: .rect(cornerRadius: 12)) // Custom shape
Button("Action") {
// Action here
}
.buttonStyle(.glass) // Apply glass button styleCombining Multiple Liquid Glass Elements
For multiple elements with Liquid Glass effects that need to interact:
GlassEffectContainer(spacing: 20.0) {
HStack(spacing: 20.0) {
Image(systemName: "cloud")
.frame(width: 60, height: 60)
.glassEffect()
Image(systemName: "sun")
.frame(width: 60, height: 60)
.glassEffect()
}
}To combine specific elements into a unified effect:
GlassEffectContainer(spacing: 20.0) {
HStack(spacing: 20.0) {
ForEach(items.indices, id: \.self) { item in
Image(systemName: items[item])
.frame(width: 60, height: 60)
.glassEffect()
.glassEffectUnion(id: item < 2 ? "group1" : "group2", namespace: namespace)
}
}
}Handling Different Platforms and Contexts
Widgets with Liquid Glass need to adapt to different platforms:
iOS and iPadOS
- Support both full color and accented rendering modes
- Test on Home Screen and Lock Screen
- Ensure readability in both light and dark appearances
macOS
- Verify font sizes and layout in macOS widget sizes
- Test in both standard and accented rendering modes
visionOS
- Support proximity awareness using the
levelOfDetailenvironment variable:
@Environment(\.levelOfDetail) var levelOfDetail
var fontSize: Font {
levelOfDetail == .simplified ? .largeTitle : .title
}Testing Liquid Glass in Widgets
To thoroughly test your widget's Liquid Glass implementation:
- Test in both light and dark mode
- Test on Home Screen and Lock Screen
- Test with different accent colors
- Test with different background images
- Test in StandBy mode on compatible devices
- Test in visionOS with different mounting styles and distances