TechnologiesSwiftUI

ZoomNavigationTransition struct

iOSmacOStvOSwatchOSvisionOS✓ renders

A navigation transition that zooms the appearing view from a given

How it works

ZoomNavigationTransition is the transition style that drives the zoom navigation effect, in which a source view appears to expand into the full destination as you push onto a navigation stack and contract back to its origin as you pop. Rather than the standard slide, it visually connects a starting element to its destination so the navigation reads as one continuous, content-aware motion. Reach for it when a tapped element — a card, thumbnail, or photo — should feel like it grows into the screen it presents. You don't instantiate the type directly; you request it through the .zoom navigation transition and pair it with a matched source identity.

  1. Establish a shared identity with @Namespace

    The zoom transition needs to match the source and destination across two different views, so it relies on a namespace to tie them together. Declare an @Namespace property — here namespace — and use that same value on both ends of the navigation so SwiftUI knows which on-screen element is zooming into which destination.

  2. Tag the source with matchedTransitionSource(id:in:)

    Mark the view the transition should grow out of by applying .matchedTransitionSource(id: "card", in: namespace). The id ("card") names this particular source, and the namespace scopes it; this is the anchor frame that the zoom expands from and contracts back to. In the example it sits on the NavigationLink's tappable label.

  3. Request the style with navigationTransition(.zoom(sourceID:in:))

    On the destination content, apply .navigationTransition(.zoom(sourceID: "card", in: namespace)). The .zoom factory produces a ZoomNavigationTransition, and its sourceID and in arguments must match the values you gave the source — "card" and namespace — so the animation pairs the two views. The destination (Color.orange) becomes the frame the source zooms into.

  4. Let it run inside a NavigationStack push

    ZoomNavigationTransition applies to a navigation push, so the matched source and the destination's navigationTransition live within a NavigationStack. When the NavigationLink activates, the framework interpolates from the source's frame to the destination's, and reverses it on pop — no per-frame animation code required.

Try it — Change the destination's .navigationTransition(.zoom(sourceID: "card", in: namespace)) to a mismatched id like sourceID: "other" and watch the zoom fall back to the default push, confirming that the transition only fires when the source and destination identities agree.

Example & preview

Press Run live & edit to compile it in your browser — then edit the Swift on the left and the preview re-renders live.

ZoomNavigationTransition.swift
struct ZoomNavigationTransitionDemo: View {
    @Namespace private var namespace
    var body: some View {
        NavigationStack {
            NavigationLink {
                Color.orange
                    .ignoresSafeArea()
                    .navigationTransition(.zoom(sourceID: "card", in: namespace))
            } label: {
                RoundedRectangle(cornerRadius: 16)
                    .fill(Color.orange)
                    .frame(width: 120, height: 120)
                    .overlay(Text("Open").foregroundStyle(.white))
            }
            .matchedTransitionSource(id: "card", in: namespace)
            .padding()
        }
    }
}
Live preview
Open 9:41
Open 9:41
swift → lexer → parser → sema → uiir → canvas Open in Studio ↗
What's new in SwiftUI 27 →