---
title: "DeferredAnimatedContent"
description: "AnimatedContent is a container that automatically animates its content when Transition.targetState changes."
type: "composable"
lastmod: "2026-05-20T01:13:52.625919Z"
---
## API Reference

### DeferredAnimatedContent

> Source set: Common

```kotlin
@ExperimentalDeferredTransitionApi
@Composable
public fun <S> DeferredTransition<S>.DeferredAnimatedContent(
    modifier: Modifier = Modifier,
    transitionSpec: AnimatedContentTransitionScope<S>.() -> ContentTransform = {
        (fadeIn(animationSpec = tween(220, delayMillis = 90)) +
                scaleIn(initialScale = 0.92f, animationSpec = tween(220, delayMillis = 90)))
            .togetherWith(fadeOut(animationSpec = tween(90)))
    },
    contentAlignment: Alignment = Alignment.TopStart,
    contentKey: (targetState: S) -> Any? = { it },
    mutableTransformSpec: AnimatedContentTransitionScope<S>.() -> MutableContentTransform? = {
        null
    },
    content: @Composable() AnimatedContentScope.(targetState: S) -> Unit,
)
```

[AnimatedContent](/jetpack-compose/androidx.compose.animation/animation/composable-functions/AnimatedContent) is a container that automatically animates its content when
[Transition.targetState](/jetpack-compose/androidx.compose.animation/animation-core/classes/Transition) changes. Its `content` for different target states is defined in a
mapping between a target state and a composable function.

**IMPORTANT**: The targetState parameter for the `content` lambda should *always* be taken into
account in deciding what composable function to return as the content for that state. This is
critical to ensure a successful lookup of all the incoming and outgoing content during content
transform.

When [Transition.targetState](/jetpack-compose/androidx.compose.animation/animation-core/classes/Transition) changes, content for both new and previous targetState will be
looked up through the `content` lambda. They will go through a [ContentTransform](/jetpack-compose/androidx.compose.animation/animation/classes/ContentTransform) so that the new
target content can be animated in while the initial content animates out. Meanwhile the container
will animate its size as needed to accommodate the new content, unless [SizeTransform](/jetpack-compose/androidx.compose.animation/animation/interfaces/SizeTransform) is set to
`null`. Once the [ContentTransform](/jetpack-compose/androidx.compose.animation/animation/classes/ContentTransform) is finished, the outgoing content will be disposed.

If [Transition.targetState](/jetpack-compose/androidx.compose.animation/animation-core/classes/Transition) is expected to mutate frequently and not all mutations should be
treated as target state change, consider defining a mapping between [Transition.targetState](/jetpack-compose/androidx.compose.animation/animation-core/classes/Transition) and
a key in `contentKey`. As a result, transitions will be triggered when the resulting key changes.
In other words, there will be no animation when switching between [Transition.targetState](/jetpack-compose/androidx.compose.animation/animation-core/classes/Transition)s that
share the same key. By default, the key will be the same as the targetState object.

 **Lifecycle:** The deferred phase starts when [DeferredTransitionState.defer](/jetpack-compose/androidx.compose.animation/animation-core/classes/DeferredTransitionState) is called. It ends and the automatic transition begins when [DeferredTransitionState.animateTo](/jetpack-compose/androidx.compose.animation/animation-core/classes/DeferredTransitionState) is called.
 **Transformations:** During this phase, you can manually manipulate the entering and exiting content's transformations (via [MutableContentTransform](/jetpack-compose/androidx.compose.animation/animation/classes/MutableContentTransform)). These transformations are applied **on top of** the transition's initial state. For example, if the enter transition starts at an alpha of 0.5, applying a manual alpha of 0.5 will result in a combined alpha of 0.25.

**Handoff:** Once the transition starts, the manually applied transformations are seamlessly
handed off to the configured `transitionSpec`. For exiting content, a "sustain unless specified"
policy is applied: if an exit transition (e.g. `fadeOut`) is specified, the hand-off will animate
towards the target value of that transition. However, if no exit transition is specified for a
given property (e.g. `slideOut` is missing), that property will sustain its last manual value
until the entire transition completes.

*Note:* While in the deferred phase, entering content remains in the [EnterExitState.PreEnter](/jetpack-compose/androidx.compose.animation/animation/classes/EnterExitState.PreEnter)
state, and exiting content remains in the [EnterExitState.Visible](/jetpack-compose/androidx.compose.animation/animation/classes/EnterExitState.Visible) state.

#### Parameters

| | |
| --- | --- |
| modifier | is applied to the Layout created by [AnimatedContent](/jetpack-compose/androidx.compose.animation/animation/composable-functions/AnimatedContent), which houses all the animating contents. |
| transitionSpec | specifies the enter/exit animations, as well as size animation (if applicable). By default, a [fadeIn](/jetpack-compose/androidx.compose.animation/animation/functions/fadeIn) and [scaleIn](/jetpack-compose/androidx.compose.animation/animation/functions/scaleIn) will be used for the entering content, and [fadeOut](/jetpack-compose/androidx.compose.animation/animation/functions/fadeOut) for the exiting content. The [ContentTransform](/jetpack-compose/androidx.compose.animation/animation/classes/ContentTransform) returned by `transitionSpec` can be created using [togetherWith](/jetpack-compose/androidx.compose.animation/animation/functions/togetherWith) with [EnterTransition](/jetpack-compose/androidx.compose.animation/animation/classes/EnterTransition) and [ExitTransition](/jetpack-compose/androidx.compose.animation/animation/classes/ExitTransition). |
| contentAlignment | specifies the alignment of the animated content. By default, it'll be aligned to the top start of the container. |
| contentKey | A key to identify the content. |
| mutableTransformSpec | A specification to control an optional manual transformation during the deferred phase (e.g., for predictive back gestures) before the main transition begins. This is only active if the [Transition](/jetpack-compose/androidx.compose.animation/animation-core/classes/Transition) was created using [rememberTransition](/jetpack-compose/androidx.compose.animation/animation-core/composable-functions/rememberTransition) with [DeferredTransitionState](/jetpack-compose/androidx.compose.animation/animation-core/classes/DeferredTransitionState). By default, this returns `null`, meaning no manual transformations are applied. |
| content | The composable function to render the content for a given state. |

## Code Examples
### DeferredAnimatedContentSample
```kotlin
@OptIn(ExperimentalDeferredTransitionApi::class)
@Composable
fun DeferredAnimatedContentSample() {
    // In a real app, these states would be driven by a gesture handler like PredictiveBackHandler
    val targetScreen by remember { mutableIntStateOf(0) }
    val isBackGestureInProgress by remember { mutableStateOf(false) }
    val swipeOffset by remember { mutableStateOf(IntOffset.Zero) }
    val transitionState = remember { DeferredTransitionState(targetScreen) }
    val transition = rememberTransition(transitionState)
    LaunchedEffect(isBackGestureInProgress, targetScreen) {
        if (isBackGestureInProgress) {
            transitionState.defer(targetScreen)
        } else {
            transitionState.animateTo(targetScreen)
        }
    }
    transition.DeferredAnimatedContent(
        transitionSpec = { slideInHorizontally { it } togetherWith slideOutHorizontally { -it } },
        mutableTransformSpec = {
            MutableContentTransform {
                if (isBackGestureInProgress && targetScreen < transitionState.targetState) {
                    // Shift the entering and exiting screens based on swipe offset
                    targetContentTransform { offset = swipeOffset }
                    initialContentTransform {
                        offset = swipeOffset.copy(swipeOffset.x / 2, swipeOffset.y / 2)
                    }
                }
            }
        },
    ) { screen ->
        Box(Modifier.size(200.dp).background(if (screen % 2 == 0) Color.Blue else Color.Green)) {
            Text("Screen $screen")
        }
    }
}
```
### TransitionExtensionAnimatedContentSample
```kotlin
@Composable
fun TransitionExtensionAnimatedContentSample() {
    @Composable
    fun CollapsedCart() {
        /* Some content here */
    }
    @Composable
    fun ExpandedCart() {
        /* Some content here */
    }
    // enum class CartState { Expanded, Collapsed }
    var cartState by remember { mutableStateOf(CartState.Collapsed) }
    // Creates a transition here to animate the corner shape and content.
    val cartOpenTransition = updateTransition(cartState, "CartOpenTransition")
    val cornerSize by
        cartOpenTransition.animateDp(
            label = "cartCornerSize",
            transitionSpec = {
                when {
                    CartState.Expanded isTransitioningTo CartState.Collapsed ->
                        tween(durationMillis = 433, delayMillis = 67)
                    else -> tween(durationMillis = 150)
                }
            },
        ) {
            if (it == CartState.Expanded) 0.dp else 24.dp
        }
    Surface(
        Modifier.shadow(8.dp, CutCornerShape(topStart = cornerSize))
            .clip(CutCornerShape(topStart = cornerSize)),
        color = Color(0xfffff0ea),
    ) {
        // Creates an AnimatedContent using the transition. This AnimatedContent will
        // derive its target state from cartOpenTransition.targetState. All the animations
        // created inside of AnimatedContent for size change, enter/exit will be added to the
        // Transition.
        cartOpenTransition.AnimatedContent(
            transitionSpec = {
                fadeIn(animationSpec = tween(150, delayMillis = 150))
                    .togetherWith(fadeOut(animationSpec = tween(150)))
                    .using(
                        SizeTransform { initialSize, targetSize ->
                            // Using different SizeTransform for different state change
                            if (CartState.Collapsed isTransitioningTo CartState.Expanded) {
                                keyframes {
                                    durationMillis = 500
                                    // Animate to full target width and by 200px in height at 150ms
                                    IntSize(targetSize.width, initialSize.height + 200) at 150
                                }
                            } else {
                                keyframes {
                                    durationMillis = 500
                                    // Animate 1/2 the height without changing the width at 150ms.
                                    // The width and rest of the height will be animated in the
                                    // timeframe between 150ms and duration (i.e. 500ms)
                                    IntSize(
                                        initialSize.width,
                                        (initialSize.height + targetSize.height) / 2,
                                    ) at 150
                                }
                            }
                        }
                    )
                    .apply {
                        targetContentZIndex =
                            when (targetState) {
                                // This defines a relationship along z-axis during the momentary
                                // overlap as both incoming and outgoing content is on screen. This
                                // fixed zOrder will ensure that collapsed content will always be on
                                // top of the expanded content - it will come in on top, and
                                // disappear over the expanded content as well.
                                CartState.Expanded -> 1f
                                CartState.Collapsed -> 2f
                            }
                    }
            }
        ) {
            // This defines the mapping from state to composable. It's critical to use the state
            // parameter (i.e. `it`) that is passed into this block of code to ensure correct
            // content lookup.
            when (it) {
                CartState.Expanded -> ExpandedCart()
                CartState.Collapsed -> CollapsedCart()
            }
        }
    }
}
```
