Layout Animations: Automatic Transitions Without Manual Timing
AI generated
RN
native
React Native · Reanimated · Layout Animations
Understanding Layout Animations
Automatic transitions with zero manual timing

Reanimated Layout Animations automatically compute smooth transitions the moment a component's size, position, or visibility changes, without developers manually orchestrating start and end values through useState or useEffect. This article covers entering, exiting, and layout transitions using a list with add and remove animations as an example, plus the performance limits for very complex lists.

12 min read entering/exiting LinearTransition FlatList animations

1. The problem with manually orchestrated transitions

Without layout animations, every transition, say removing a list item, has to be choreographed manually: first animate opacity to zero, then actually remove the item from state once the animation finishes, and at the same time make sure the remaining items smoothly shift upward instead of jumping abruptly. Coordinating this across several useState and useEffect calls is error-prone and gets more complex with every additional animation.

Reanimated Layout Animations solve exactly this problem by automatically detecting and interpolating size and position changes of a component, without the developer having to manually calculate intermediate steps. The moment a component is removed from the tree, newly inserted, or moved to a new position, Reanimated takes over animating that transition on its own.

2. Entering animations: how new elements appear

The entering prop on an Animated.View lets you define how a component enters the visible tree the first time it renders. Predefined presets such as FadeIn, SlideInRight, or ZoomIn cover most use cases and can be fine-tuned through modifier methods like .duration() or .delay().

It matters that the entering animation fires automatically on every mount of the component, not just on the app's first render. If an element gets shown again through conditional rendering, say after a filter change in a list, Reanimated plays the entering animation again, with zero extra code.


import Animated, { FadeIn, SlideInRight } from 'react-native-reanimated';

function NewMessageBubble({ text }: { text: string }) {
  return (
    <Animated.View
      entering={SlideInRight.duration(300).easing(Easing.out(Easing.cubic))}
    >
      <Text>{text}</Text>
    </Animated.View>
  );
}

3. Exiting animations: how elements disappear

The counterpart is the exiting prop, which defines an animation for the moment a component is removed from the tree, say FadeOut or SlideOutLeft. Reanimated keeps the component internally in the native view tree until the animation finishes, then removes it automatically, without the developer maintaining a timeout or extra state.

That is the key difference from a manual solution: from React's point of view, the component is gone the instant it disappears from the parent tree, while Reanimated, at the UI-thread level, delays the actual removal until the exiting animation completes.


import Animated, { FadeOut, Layout } from 'react-native-reanimated';

function TodoItem({ item, onRemove }: { item: Todo; onRemove: () => void }) {
  return (
    <Animated.View exiting={FadeOut.duration(250)} layout={Layout.springify()}>
      <TodoRow item={item} onPress={onRemove} />
    </Animated.View>
  );
}

4. Layout transitions: automatic transitions for position changes

The layout prop, usually configured with LinearTransition or Layout.springify(), makes a component automatically animate from its old to its new position and size the moment the layout changes, say because a sibling element was removed or the component's own size changes due to new text content.

Reanimated internally compares the layout before and after a React update and automatically calculates the necessary transform, without start and target values needing to be measured manually. Combined with entering and exiting, this creates a complete, consistent transition system for dynamic lists.

5. Practical example: a list with add and remove animations

The following example combines all three building blocks in a simple todo list: new entries slide in from the right through entering, removed entries fade out through exiting, and all remaining entries automatically shift to their new position through layout, without the list itself knowing any animation logic at all.

It matters that every list item has a stable key, usually the entry's ID, because Reanimated uses that key to determine whether a component is freshly mounted, continues to exist unchanged, or was removed. An unstable key, say the array index, leads to animations being applied to the wrong elements.


function TodoList({ items }: { items: Todo[] }) {
  return (
    <View>
      {items.map((item) => (
        <Animated.View
          key={item.id}
          entering={SlideInRight}
          exiting={FadeOut}
          layout={LinearTransition.springify().damping(18)}
        >
          <TodoRow item={item} />
        </Animated.View>
      ))}
    </View>
  );
}

6. Custom transitions instead of predefined presets

For cases where the predefined presets fall short, custom entering and exiting animations can be defined as a worklet that returns start and end values for arbitrary style properties. That opens up the ability to animate several properties at once or match an animation to a specific design language not covered by the shipped presets.

These custom animations run just as fully on the UI thread as the predefined presets do, since they too ultimately get compiled as worklets, which means the performance characteristics and pitfalls of the worklet model carry over directly.


const CustomEntering = (targetValues: LayoutAnimationsValues) => {
  'worklet';
  const animations = {
    opacity: withTiming(1, { duration: 300 }),
    transform: [{ scale: withSpring(1) }],
  };
  const initialValues = { opacity: 0, transform: [{ scale: 0.8 }] };
  return { initialValues, animations };
};

7. Performance limits for complex lists

For short to medium lists rendered entirely as regular React components, layout animations work with virtually no limitations. For very long lists rendered through a virtualized FlatList, entering and exiting hit a limit: virtualized lists constantly mount and unmount elements outside the visible area, which makes Reanimated attempt to animate elements the user never actually sees.

In practice, that means applying layout animations deliberately, only for visible, short-lived changes, say adding or removing an entry through a direct user action, instead of applying them blanket-style to every item of a very long, virtualized list. With several hundred simultaneously animated elements, the number of parallel UI-thread calculations can also become noticeable even on powerful devices.

8. Debugging layout animations and common failure patterns

A common problem is that a layout transition simply does not show up because the affected component is not directly an Animated.View, but wrapped in a plain View that itself receives no layout prop. Reanimated can only animate layout changes for components that are themselves rendered as an animated component, not for arbitrary nested child elements.

A second widespread issue involves the New Architecture: layout animations build on Fabric and can behave inconsistently on older, not-yet-migrated parts of an app. Testing on both platforms with the New Architecture enabled is therefore advisable before shipping layout animations in critical lists.

9. Combining layout animations with gesture-driven changes

Layout animations combine well with gesture-driven interactions, say when a list item removed through a swipe gesture is finally hidden through exiting once the swipe completes, while the remaining items automatically shift through layout. The gesture itself only controls visibility and state, the actual transition animation of the list stays entirely with Reanimated.

This combination of manually driven gesture animations and automatic layout animations is a good example of how the two concepts complement rather than replace each other: gestures for direct, physically plausible interaction, layout animations for the structural consequence of that interaction.

Situation Recommended prop Typical preset Note
A new element appears entering FadeIn, SlideInRight Fires on every mount, not just app start
An element gets removed exiting FadeOut, SlideOutLeft Component stays in the native tree until the animation ends
Sibling elements shift layout LinearTransition, Layout.springify() Needs a stable key per element
Very long, virtualized list Targeted, not blanket No preset on every item FlatList mounts/unmounts outside the viewport constantly
Custom, non-preset animation Custom worklet own initialValues/animations Runs entirely on the UI thread
Combination with a swipe gesture exiting after gesture end depends on the use case Gesture drives state, layout animation drives the transition

Mironsoft

React Native app development and Magento integration

A mobile app for the Magento shop that actually runs smoothly?

We build React Native apps cleanly connected to the Magento REST or GraphQL API, from the first line of code to publishing on the App Store and Google Play.

App Concept

Plan the architecture and feature scope of a Magento-connected app together.

Magento API Integration

Cleanly connect product catalog, cart, and checkout to the shop API.

Store Publishing

Guide the App Store and Google Play release process without pitfalls.

10. Summary

Layout Animations

Core idea

Reanimated automatically computes transitions on mount, unmount, and position change, with zero manual timing.

Three building blocks

entering for new elements, exiting for removed elements, layout for position changes of existing elements.

Key rule

Every list item needs a stable key, otherwise animations get applied to the wrong elements.

Performance limit

Apply deliberately, not blanket-style, in very long virtualized lists, since FlatList constantly mounts and unmounts.

11. FAQ: Layout Animations

1What is the difference between entering and layout?
entering controls how a component appears on mount, while layout controls how an already existing component moves when its position or size changes due to a change in the surrounding layout.
2Why is my exiting animation not showing up?
Usually because the component is not directly an Animated.View with an exiting prop, but wrapped in a plain View instead. Reanimated can only animate components that are themselves rendered as an animated element.
3Do I need a stable key for every list item?
Yes, absolutely. Reanimated uses the key to determine whether a component is freshly mounted, continues to exist, or was removed. An unstable key like the array index leads to animations being applied to the wrong elements.
4Do layout animations work inside a FlatList?
Generally yes, though with limitations for very long lists, since virtualization constantly mounts and unmounts elements outside the visible area, which can cause unnecessary animation calculations.
5Can I write my own entering and exiting animations?
Yes, through a worklet function that returns initialValues and animations. That lets you animate arbitrary style properties, not just the ones covered by the predefined presets.
6How do I combine layout animations with a swipe-to-delete gesture?
The gesture controls the item's visibility and state, while exiting handles the actual fade-out transition and layout makes sure the remaining items automatically shift into place.
7Do layout animations need the New Architecture?
They work most reliably with Fabric and the New Architecture. On older, not-yet-migrated parts of an app, behavior can be inconsistent, so testing on both platforms is recommended.
8What happens when two list items use entering and exiting at the same time?
Each element animates independently according to its own state, while layout automatically makes sure the remaining elements adjust consistently to the list's new overall height.
9How do I control the duration of a layout transition?
Through modifier methods like .duration() or .springify() with parameters such as damping and stiffness on the given preset, for example LinearTransition.springify().damping(18).
10Are layout animations still performant with several hundred simultaneously animated elements?
Not without limits. With very many simultaneously animated elements, the number of parallel UI-thread calculations rises noticeably, which is why a targeted rather than blanket approach on visible, short-lived changes is recommended.