SwiftUI.cc
Snippets
LayoutLayout ModifiersIntermediate

SwiftUI Overlay, Background, and zIndex

Layer views deliberately with background, overlay, and zIndex while keeping the base layout stable.

4 min readUpdated 2026-06
Unread badge
import SwiftUI

struct InboxIcon: View {
    let unreadCount: Int

    var body: some View {
        Image(systemName: "tray.full")
            .font(.title2)
            .padding(12)
            .background(.thinMaterial, in: RoundedRectangle(cornerRadius: 14))
            .overlay(alignment: .topTrailing) {
                if unreadCount > 0 {
                    Text("\(unreadCount)")
                        .font(.caption2.bold())
                        .padding(5)
                        .background(.red, in: Circle())
                        .foregroundStyle(.white)
                        .offset(x: 6, y: -6)
                }
            }
    }
}
Use this when

A badge, border, shadow surface, or selection ring should not change the main layout.

A background needs shape clipping without wrapping the view in another container.

Overlapping siblings need an explicit stacking order.

Avoid this when

The layered content should take space in the layout.

The overlay needs complex independent navigation.

A zIndex value is hiding a deeper layout ordering problem.

Implementation notes

background and overlay inherit the base view's size unless you explicitly change their layout.
Use aligned overlays for badges and affordances so the main view remains easy to reason about.
zIndex works among siblings; it does not globally float a view above the whole app.

Checklist

Make sure overlays do not hide tappable controls unexpectedly.

Check right-to-left layout when alignment matters.

Use contentShape if the visible tap area differs from the base view.

Related reference