---
title: "AnimatedContent"
description: "[AnimatedContent] is a container that automatically animates its content when [targetState]
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 [targetState] changes, content for both new and previous targetState will be looked up
through the [content] lambda. They will go through a [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] is set to
`null`. Once the [ContentTransform] is finished, the outgoing content will be disposed.

If [targetState] is expected to mutate frequently and not all mutations should be treated as
target state change, consider defining a mapping between [targetState] 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 [targetState]s that share the same key. By default,
the key will be the same as the targetState object.

By default, the [ContentTransform] will be a delayed [fadeIn] of the target content and a delayed
[scaleIn] [togetherWith] a [fadeOut] of the initial content, using a [SizeTransform] to animate
any size change of the content. This behavior can be customized using [transitionSpec]. If
desired, different [ContentTransform]s can be defined for different pairs of initial content and
target content.

[AnimatedContent] displays only the content for [targetState] when not animating. However, during
the transient content transform, there will be more than one set of content present in the
[AnimatedContent] container. It may be sometimes desired to define the positional relationship
among the different content and the overlap. This can be achieved by defining [contentAlignment]
and [zOrder][ContentTransform.targetContentZIndex]. By default, [contentAlignment] aligns all
content to [Alignment.TopStart], and the `zIndex` for all the content is 0f. __Note__: The target
content will always be placed last, therefore it will be on top of all the other content unless
zIndex is specified.

Different content in [AnimatedContent] will have access to their own [AnimatedContentScope]. This
allows content to define more local enter/exit transitions via
[AnimatedContentScope.animateEnterExit] and [AnimatedContentScope.transition]. These custom
enter/exit animations will be triggered as the content enters/leaves the container.

[label] is an optional parameter to differentiate from other animations in Android Studio.


Below is an example of customizing [transitionSpec] to imply a spatial relationship between the
content for different states:"
type: "composable"
---

<div class='type'>Composable Function</div>


<a id='references'></a>

<div class='sourceset sourceset-common'>Common</div>


```kotlin
@Composable
public fun <S> AnimatedContent(
    targetState: S,
    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,
    label: String = "AnimatedContent",
    contentKey: (targetState: S) -> Any? = { it },
    content: @Composable() AnimatedContentScope.(targetState: S) -> Unit,
)
```


`AnimatedContent` is a container that automatically animates its content when `targetState`
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 `targetState` changes, content for both new and previous targetState will be looked up
through the `content` lambda. They will go through a `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` is set to
`null`. Once the `ContentTransform` is finished, the outgoing content will be disposed.

If `targetState` is expected to mutate frequently and not all mutations should be treated as
target state change, consider defining a mapping between `targetState` 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 `targetState`s that share the same key. By default,
the key will be the same as the targetState object.

By default, the `ContentTransform` will be a delayed `fadeIn` of the target content and a delayed
`scaleIn` `togetherWith` a `fadeOut` of the initial content, using a `SizeTransform` to animate
any size change of the content. This behavior can be customized using `transitionSpec`. If
desired, different `ContentTransform`s can be defined for different pairs of initial content and
target content.

`AnimatedContent` displays only the content for `targetState` when not animating. However, during
the transient content transform, there will be more than one set of content present in the
`AnimatedContent` container. It may be sometimes desired to define the positional relationship
among the different content and the overlap. This can be achieved by defining `contentAlignment`
and `zOrder`. By default, `contentAlignment` aligns all
content to `Alignment.TopStart`, and the `zIndex` for all the content is 0f. __Note__: The target
content will always be placed last, therefore it will be on top of all the other content unless
zIndex is specified.

Different content in `AnimatedContent` will have access to their own `AnimatedContentScope`. This
allows content to define more local enter/exit transitions via
`AnimatedContentScope.animateEnterExit` and `AnimatedContentScope.transition`. These custom
enter/exit animations will be triggered as the content enters/leaves the container.

`label` is an optional parameter to differentiate from other animations in Android Studio.


Below is an example of customizing `transitionSpec` to imply a spatial relationship between the
content for different states:



<div class='sourceset sourceset-common'>Common</div>


```kotlin
@Composable
public fun <S> Transition<S>.AnimatedContent(
    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 },
    content: @Composable() AnimatedContentScope.(targetState: S) -> Unit,
)
```


`AnimatedContent` is a container that automatically animates its content when
`Transition.targetState` 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` changes, content for both new and previous targetState will be
looked up through the `content` lambda. They will go through a `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` is set to
`null`. Once the `ContentTransform` is finished, the outgoing content will be disposed.

If `Transition.targetState` is expected to mutate frequently and not all mutations should be
treated as target state change, consider defining a mapping between `Transition.targetState` 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`s that
share the same key. By default, the key will be the same as the targetState object.

By default, the `ContentTransform` will be a delayed `fadeIn` of the target content and a delayed
`scaleIn` `togetherWith` a `fadeOut` of the initial content, using a `SizeTransform` to animate
any size change of the content. This behavior can be customized using `transitionSpec`. If
desired, different `ContentTransform`s can be defined for different pairs of initial content and
target content.

`AnimatedContent` displays only the content for `Transition.targetState` when not animating.
However, during the transient content transform, there will be more than one sets of content
present in the `AnimatedContent` container. It may be sometimes desired to define the positional
relationship among different content and the style of overlap. This can be achieved by defining
`contentAlignment` and `zOrder`. By default,
`contentAlignment` aligns all content to `Alignment.TopStart`, and the `zIndex` for all the
content is 0f. __Note__: The target content will always be placed last, therefore it will be on
top of all the other content unless zIndex is specified.

Different content in `AnimatedContent` will have access to their own `AnimatedContentScope`. This
allows content to define more local enter/exit transitions via
`AnimatedContentScope.animateEnterExit` and `AnimatedContentScope.transition`. These custom
enter/exit animations will be triggered as the content enters/leaves the container.




## Code Examples
### AnimateIncrementDecrementSample
```kotlin
@Composable
fun AnimateIncrementDecrementSample() {
    Column(Modifier.padding(20.dp), horizontalAlignment = Alignment.CenterHorizontally) {
        var count by remember { mutableStateOf(0) }
        // The `AnimatedContent` below uses an integer count as its target state. So when the
        // count changes, it will animate out the content associated with the previous count, and
        // animate in the content associated with the target state.
        AnimatedContent(
            targetState = count,
            transitionSpec = {
                // We can define how the new target content comes in and how initial content
                // leaves in the ContentTransform. Here we want to create the impression that the
                // different numbers have a spatial relationship - larger numbers are
                // positioned (vertically) below smaller numbers.
                if (targetState > initialState) {
                        // If the incoming number is larger, new number slides up and fades in while
                        // the previous (smaller) number slides up to make room and fades out.
                        slideInVertically { it } + fadeIn() togetherWith
                            slideOutVertically { -it } + fadeOut()
                    } else {
                        // If the incoming number is smaller, new number slides down and fades in
                        // while
                        // the previous number slides down and fades out.
                        slideInVertically { -it } + fadeIn() togetherWith
                            slideOutVertically { it } + fadeOut()
                        // Disable clipping since the faded slide-out is desired out of bounds, but
                        // the size transform is still needed from number getting longer
                    }
                    .using(SizeTransform(clip = false)) // Using default spring for the size change.
            },
        ) { targetCount ->
            // This establishes a mapping between the target state and the content in the form of a
            // Composable function. IMPORTANT: The parameter of this content lambda should
            // *always* be used. During the content transform, the old content will be looked up
            // using this lambda with the old state, until it's fully animated out.
            // Since AnimatedContent differentiates the contents using their target states as the
            // key, the same composable function returned by the content lambda like below will be
            // invoked under different keys and therefore treated as different entities.
            Text("$targetCount", fontSize = 20.sp)
        }
        Spacer(Modifier.size(20.dp))
        Row(horizontalArrangement = Arrangement.SpaceAround) {
            Button(onClick = { count-- }) { Text("Minus") }
            Spacer(Modifier.size(60.dp))
            Button(onClick = { count++ }) { Text("Plus ") }
        }
    }
}
```
### SimpleAnimatedContentSample
```kotlin
@Composable
fun SimpleAnimatedContentSample() {
    // enum class ContentState { Foo, Bar, Baz }
    @Composable
    fun Foo() {
        Box(Modifier.size(200.dp).background(Color(0xffffdb00)))
    }
    @Composable
    fun Bar() {
        Box(Modifier.size(40.dp).background(Color(0xffff8100)))
    }
    @Composable
    fun Baz() {
        Box(Modifier.size(80.dp, 20.dp).background(Color(0xffff4400)))
    }
    var contentState: ContentState by remember { mutableStateOf(ContentState.Foo) }
    AnimatedContent(contentState) {
        when (it) {
            // Specifies the mapping between a given ContentState and a composable function.
            ContentState.Foo -> Foo()
            ContentState.Bar -> Bar()
            ContentState.Baz -> Baz()
        }
    }
}
```
### 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()
            }
        }
    }
}
```

