> ## Documentation Index
> Fetch the complete documentation index at: https://docs.metabind.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# withAnimation

> Wraps state mutations in an animation context so the resulting UI changes animate.

```typescript theme={null}
withAnimation(body: () => void): Component;
withAnimation(animation: AnimationComponent, body: () => void): Component;
```

<ParamField path="animation" type="AnimationComponent" optional>
  An animation created with `Spring()`, `InterpolatingSpring()`, `EaseIn()`, `EaseInOut()`, `EaseOut()`, `Linear()`, `Bouncy()`, or `Snappy()`. If omitted, a default spring animation is used.
</ParamField>

<ParamField path="body" type="() => void" required>
  A function containing state mutations. All UI changes resulting from these mutations will be animated.
</ParamField>

## Returns

A `Component` that executes the body function within the animation context.

## Usage

### Default animation

```typescript theme={null}
const body = () => {
    const [count, setCount] = useState(0)

    return VStack([
        Text(String(count)).font("largeTitle"),
        Button("Animate +1", () => {
            withAnimation(() => setCount(count + 1))
        })
    ])
}
```

### With a spring animation

```typescript theme={null}
const body = () => {
    const [isExpanded, setIsExpanded] = useState(false)

    return VStack([
        Button(isExpanded ? "Collapse" : "Expand", () => {
            withAnimation(Spring({ response: 0.5 }), () => {
                setIsExpanded(!isExpanded)
            })
        }),
        Rectangle()
            .fill(Color("blue"))
            .frame({ height: isExpanded ? 200 : 50 })
    ])
}
```

### With an easing curve

```typescript theme={null}
const body = () => {
    const [offset, setOffset] = useState(0)

    return VStack([
        Rectangle()
            .fill(Color("blue"))
            .frame({ width: 50, height: 50 })
            .offset({ x: offset, y: 0 }),
        Button("Move Right", () => {
            withAnimation(EaseInOut({ duration: 0.5 }), () => {
                setOffset(offset + 100)
            })
        })
    ])
}
```

## Notes

* Multiple state changes within the same `withAnimation` block are batched into a single animated transition.
* The animation context applies to all UI changes resulting from the state mutations, not just the direct parent view.
* If no animation is specified, a default spring animation is used.
* For details on available animation constructors and their options, see [animations](/bindjs/functions/animations).

## See Also

* [animations](/bindjs/functions/animations) -- all animation constructors and chainable modifiers
* [useState](/bindjs/functions/useState) -- component-local state
