Skip to content

Scoped Animations (SwiftUI)

A SwiftUI guide for coding agents. Also covers animation viewbuilder closure, limit animation scope, unexpected animations fix, animation value parameter, scoped transaction, multi step animation ios.

The animation(_:body:) modifier scopes an animation to a ViewBuilder closure, so it animates only the modifiers inside that block. It solves both problems of the old forms: animating unrelated changes, and stacking one animation(value:) per property.

Why the Old Forms Leak

A bare animation(.default) on a container animates every change inside it, including ones you never intended, such as an environment value change. Binding with value: fixes that but scopes to one value only.

VStack {
  Button("Animate") { isHidden.toggle() }
  HugeView().opacity(isHidden ? 0.0 : 1.0)
  AnotherHugeView()
}
.animation(.default, value: isHidden)

With several animatable properties, the value: form needs one modifier per property, which is correct but clumsy.

The Scoped Form

The closure variant applies the animation only to the modifiers written inside the closure. The content parameter is a placeholder for the view the modifier is attached to.

SomeView()
  .animation(.default) { content in
    content
      .opacity(firstStep ? 1.0 : 0.0)
      .blur(radius: secondStep ? 0 : 20.0)
  }

Any state change that touches those two modifiers animates. Nothing outside the closure picks the animation up, so the rest of the hierarchy stays still.

Scoped Transactions

The transaction(_:body:) modifier does the same for transactions: mutate the transaction, and the change applies only inside the body closure.

SomeView()
  .transaction { t in
    t.animation = t.animation?.speed(2)
  } body: { content in
    content
      .opacity(firstStep ? 1.0 : 0.0)
      .blur(radius: secondStep ? 0 : 20.0)
  }

Both scoped forms shipped with the iOS 17 generation of platforms and are not backward compatible. On earlier targets, fall back to animation(_:value:) per property.

Use this guidance in your coding agent

Install the Better Design MCP once. Your agent then loads this page with one call.

get-swiftui-guide({ topic: "swiftui-scoped-animations" })
claude mcp add --scope user better-design --transport http https://better-design.com/api/mcp --header "Authorization: Bearer <YOUR_API_KEY>"
Browse related design systems