How it works
MatchedTransitionSourceConfiguration describes the appearance of the source view that anchors a matched geometry navigation transition — most notably the zoom transition. When you mark a view as a transition source, SwiftUI hands you a value of this type so you can shape how that source looks as the animation hands off to the destination, controlling details like corner shape and clipping along the way. Reach for it through the closure form of matchedTransitionSource(id:in:) whenever the default source styling doesn't match the geometry you're animating from, so the morph between the source and its zoomed destination reads as a single continuous element.
Establish a shared namespace with @Namespace
A matched transition pairs a source and a destination by a common identifier living in the same animation namespace. Declare one with
@Namespace private var namespaceand pass it to both ends so SwiftUI knows theButton("Open Photo")source and theColor.bluedestination are the same element mid-flight.Mark the source with matchedTransitionSource(id:in:)
Attach
matchedTransitionSource(id: "photo", in: namespace)to the view you're animating away from. This registers that view as the geometric origin of the transition; theidstring and thenamespacetogether must match the destination's transition for SwiftUI to connect them.Style the source through the configuration closure
The trailing-closure form of
matchedTransitionSourceyields aMatchedTransitionSourceConfigurationasconfig. Return a modified configuration from the closure — hereconfig.cornerRadius(16)rounds the source's corners — and SwiftUI carries that styling into the transition so the source's shape lines up with how the zoomed view appears.Pair it with navigationTransition(.zoom) on the destination
The configuration only matters when a destination opts into the matched animation. The pushed
Color.blueview appliesnavigationTransition(.zoom(sourceID: "photo", in: namespace)), whosesourceIDandnamespaceresolve back to the configured source, completing the zoom hand-off whenshowDetailflips to true.
config.cornerRadius(16) up to config.cornerRadius(40) and watch the source's rounding — and the shape it morphs from during the zoom — change to match.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.
struct MatchedTransitionSourceConfigurationDemo: View {
@Namespace private var namespace
@State private var showDetail = false
var body: some View {
NavigationStack {
Button("Open Photo") {
showDetail = true
}
.matchedTransitionSource(id: "photo", in: namespace) { config in
config
.cornerRadius(16)
}
.padding()
.navigationDestination(isPresented: $showDetail) {
Color.blue
.frame(width: 240, height: 240)
.navigationTransition(.zoom(sourceID: "photo", in: namespace))
}
}
}
}