System Materials and Backgrounds in iOS 15 for SwiftUI | SwiftUI Bootcamp #55
System materials are the frosted-glass effect you see in Control Center, Notification Center, and Apple Maps — a translucent blur that shows the content behind it while making foreground content readable. iOS 15 made these materials available to SwiftUI developers with a single modifier. After this lesson you'll know how to apply blur materials, choose the right thickness, and combine them with background content to create native-feeling overlays.
What You'll Learn
- What system materials are and why they automatically adapt to light and dark mode
- How to apply
.ultraThinMaterial,.thinMaterial,.regularMaterial,.thickMaterial, and.ultraThickMaterialas backgrounds - How to build a bottom sheet overlay effect using a material background over a full-screen image
- How
.ignoresSafeArea()and.frame()interact to create a sheet-like presentation
Mental Model
Think of system materials like frosted glass in architecture. A clear glass window shows the outdoors perfectly but also exposes everything inside. Frosted glass blurs the view through it, creating privacy and visual hierarchy while still hinting at what's behind. The five material thicknesses — ultra thin, thin, regular, thick, ultra thick — are like different grades of frosting: ultra thin lets the most light and color through, ultra thick is almost opaque.
The key property of system materials is that they are "live" — the blur renders what is actually behind the view at that moment. If the content behind scrolls or moves, the blur adapts in real time. This is fundamentally different from faking it with a semi-transparent color: materials interact with depth and layering in a way a flat Color.white.opacity(0.5) can never replicate.
Detailed Explanation
System materials in iOS 15 are accessed through SwiftUI's ShapeStyle protocol as named values: .ultraThinMaterial, .thinMaterial, .regularMaterial, .thickMaterial, and .ultraThickMaterial. They work as background values: .background(.ultraThinMaterial). The material renders a real-time blur of whatever content is behind the view in the view hierarchy.
Materials automatically adapt to both light and dark mode without any conditional logic. In light mode they appear as a light frosted glass; in dark mode they adapt to a darker tint. This is one of the major advantages over manually specifying semi-transparent colors that look wrong in one or both appearances.
The pattern in this lesson is a classic "bottom sheet" layout: a full-screen background image set behind the entire view using .ignoresSafeArea(), and a white card VStack that slides up from the bottom with a material background applied. The key to this effect is that the material blur shows the image behind it — the color is not artificially added; it comes from the actual content underneath.
Materials work with any View through the .background() modifier. You can also use ZStack layers — place an image or gradient in the background, then put a view with a material background on top. The material's blur effect is applied to whatever is directly behind it in the compositing order.
When NOT to use materials: on solid-color backgrounds (the blur has nothing to blur, so the material just adds translucency over a flat color), on very dense content where the blur effect would be distracting rather than clarifying, or when accessibility contrast requirements demand solid backgrounds. Always test materials against their actual background content, not just in a blank preview.
Code Structure
BackgroundMaterialsBootcamp.swift creates a bottom-panel overlay. A full-screen image named "therock" fills the background (you would substitute any image from your asset catalog). A bottom-anchored VStack with .ultraThinMaterial background and cornerRadius(30) creates the frosted glass panel. A drag handle (a small RoundedRectangle) at the top of the panel hints at swipeable sheet behavior.
Complete Code
BackgroundMaterialsBootcamp.swift
import SwiftUI
struct BackgroundMaterialsBootcamp: View {
var body: some View {
VStack {
Spacer() // pushes the material panel to the bottom of the screen
VStack {
RoundedRectangle(cornerRadius: 4)
.frame(width: 50, height: 4) // drag handle: a thin pill shape, common in sheet presentations
.padding()
Spacer()
}
.frame(height: 350) // panel height; covers roughly the bottom 40–50% of the screen
.frame(maxWidth: .infinity) // extends to full screen width
.background(.ultraThinMaterial) // renders a real-time blur of the image behind this panel
.cornerRadius(30) // rounds the top corners to give a card/sheet appearance
}
.ignoresSafeArea() // allows the background image to extend under the home indicator and status bar
.background(
Image("therock") // replace "therock" with any image in your Assets.xcassets
)
}
}
struct BackgroundMaterialsBootcamp_Previews: PreviewProvider {
static var previews: some View {
BackgroundMaterialsBootcamp()
}
}Code Walkthrough
Spacer()at the top of the outerVStack— Pushes all content to the bottom. Without this spacer, the material panel would appear at the top of the screen. This is the simplest way to bottom-align a view inside aVStackwithout usingGeometryReaderor manual offsets.Inner
VStackwith the drag handle — The drag handle is aRoundedRectangle(cornerRadius: 4)sized to 50×4 points. This visual convention comes from UIKit's.pageSheetpresentation — it signals to users that the panel can be dragged. For a fully interactive draggable sheet you would add aDragGesture..frame(height: 350)— Controls how much of the screen the panel covers. 350pt is roughly half of most iPhone screen heights. Adjust this based on how much content the panel will contain in your real use case..background(.ultraThinMaterial)— The one-line material application..ultraThinMaterialprovides the highest transparency and the lightest blur — most of the background image shows through with just a slight frost. Try.regularMaterialor.thickMaterialfor a more opaque panel..cornerRadius(30)— Applied after.frame()so it clips the material layer at the final size. The 30pt radius creates the characteristic rounded-top-corners appearance of iOS sheets. The bottom corners are square (covered by the screen edge), which is the correct behavior..ignoresSafeArea()on the outerVStack— Allows the background image to extend all the way to the screen edges, including behind the status bar and home indicator. Without this, the image would be clipped to the safe area and there would be empty space at the top and bottom..background(Image("therock"))— Places the image behind the entire view hierarchy. This is not a full-screen image by default — you may need to add.resizable()and.scaledToFill()to the image to make it cover the full screen. The image is what the material blurs.
Common Mistakes
Mistake: Applying .background(.ultraThinMaterial) over a solid color background and expecting a blur effect
Materials blur what is behind them. If the view behind is a solid Color.white, the material shows a slightly tinted white — there's nothing to blur. Materials only produce the frosted glass visual effect when there is rich content (images, gradients, complex UIs) behind them. Test materials against their actual production background.
Mistake: Placing the material view and background image in the wrong Z-order
The material panel must be in front of the image in the compositing order. Using .background(Image("...")) on the outer container ensures the image is behind everything. If you use ZStack instead, make sure the image is the first (bottommost) layer and the material view is above it.
Mistake: Forgetting .ignoresSafeArea() on the background image, leaving gaps at the top and bottom
Without .ignoresSafeArea(), the background image is clipped to the safe area boundaries, creating white or black bars at the top (below the status bar notch) and bottom (above the home indicator). Always extend background content to the full screen with .ignoresSafeArea() for edge-to-edge designs.
Key Takeaways
- System materials (
.ultraThinMaterialthrough.ultraThickMaterial) render real-time blurs of content behind them and automatically adapt to light and dark mode — they replace manual semi-transparent color hacks. - Apply materials via
.background(.regularMaterial)on any view; the blur effect only looks correct when there is visual content (images, gradients) behind the view in the compositing stack. - The bottom sheet pattern — a
VStackwith aSpacerat top, a materialVStackat the bottom,.cornerRadius, and.ignoresSafeArea()on the container — is a reusable template for iOS-native overlay panels.
Last updated: June 27, 2026