Show Table of Contents

React Flip Children
Documentation

v0.3.5

by Alfonsus Ardani

The documentation for React Flip Children

Last updated: 2025-02-19

Read Me

Overview

React Flip Children is a React component that aims to provide a simple way to animate change in children props allowing for smooth transitions between states while also keeping the Developer Experience (DX) in mind.

The package leverages React's lifecycle hooks, the FLIP technique, Web Animation API, and CSS transitions to provide a seamless and customizable animation experience.

Install the package via your package manager of choice.

npm install react-flip-children

Features

React Flip Children was inspired by Josh Comeau's awesome React Flip Move and offers:

  • Automatic detection of child additions, deletions, and movements.
  • Reorder animation using Web Animation API that is performant and smooth.
  • Full support for customizable entry/exit animations entirely using custom data- attributes.
  • Ability to provide continuous animations for children that are in the middle of animating
  • Support for custom animation durations and easing.

Usage

The usage of React Flip Children is simple. Simply wrap the children you want to animate in the AnimateChildren component and get reorder animation for free.

import React, { useState } from 'react'
import { AnimateChildren } from 'react-flip-children'

export default function App() {
  const [items, setItems] = useState([1, 2, 3])

  return (
    <AnimateChildren>
      {items.map(item => (
        <div key={item}>
          Item {item}
        </div>
      ))}
    </AnimateChildren>
  );
}

Enter/Leave Animations

React Flip Children allows you to provide custom animations for children entering and leaving the DOM. This is done by adding a CSS class that reads the data- attribute provided by the component.

The data-adding attribute is added to the child when it is added to the DOM and data-removing is added when the child is removed from the DOM. You can then target these attributes with CSS for custom animations.

Here is an example in tailwind of how you can provide custom animations for entering and leaving children:

<div className="
  data-[adding]:opacity-0
  opacity-100
  data-[deleting]:opacity-0
" />

Here is an example in CSS:

card {
  opacity: 1;
}
card[data-adding], 
card[data-deleting] {
  opacity: 0;
}

Animatable Children

React Flip Children requires injecting refs into child elements to enable animations. Therefore, React elements passed to <AnimateChildren> must have refs forwarded to actual HTML elements.:

Here are examples of animatable elements:

<div>Hello World</div>

// React >19 
function Card(props: ComponentProps<"div">) {
  return <div {...props} />
}

// React <19
const Card = forwardRef((props, ref) => {
  return <div ref={ref} {...props} />
})

Demo

Compatibility

  • React Flip Children is compatible with all modern browsers, including Internet Explorer 11.
  • The library is bundled to the ESNext module format.

Gotchas

  • CSS Transitions are unable to be persisted across re-renders. If a child is in the middle of a transition and the parent re-renders, there is a chance that the animation will be interrupted.
  • Async components (React 18+) do not pass keys to their actuall React elements, causing potential issues with React Flip Children. To work around this limitation, you can wrap each async component with in a <div>
  • React Flip Children uses the translate CSS property for child reordering. If the parent component is set to overflow: auto, it may cause scrolling issues. It is recommended to set the parent to overflow: hidden or overflow:visible to avoid this issue.
  • Overriding the translate property in child components may not work as expected due to the use of WAAPI.
  • While it’s not necessary to provide a key to children of the <AnimateChildren> component (it will auto-generate keys), it is still recommended to provide keys to avoid unwanted behavior.
  • Proper animations require user-defined CSS for transitions.

Known Issues

  • Using both async components and useSearchParams from Next.js can cause hanging.
  • Argument of type 'Element' is not assignable to parameter of type 'ReactNode'. This is a TypeScript issue that can be resolved by casting the element to ReactNode or changing moduleResolution in tsconfig.json to other values than node or classic.

Contributions

Contributors are welcome! Please discuss new features with me ahead of time, and submit PRs for bug fixes.

License

This package is licensed under the MIT License.

Acknowledgements

Special thanks to friends and family for their guidance and support during the development of this project.

If you find any issues or have feature requests, please open an issue on GitHub.

Integration

shadcn/ui

React Flip Children can be integrated with shadcn/ui with minimal effort.

shadcn/ui Integration Guide ->

HeroUI

React Flip Children can be integrated with HeroUI with minimal effort.

HeroUI Integration Guide ->

Mantine

React Flip Children can be integrated with Mantine with minimal effort.

Mantine Integration Guide ->

API Reference

<AnimateChildren/>

<AnimateChildren/> is a React component, and is configured via the following props:

children?: ReactNode

The children to animate. This can be any valid ReactNode, but only valid children will be animated. Others may be rendered but not animated, or omitted entirely.

Omitted Nodes

null, undefined, and boolean values will be omitted.

Rendered but Not Animated

string, number, bigint, ReactPortal, and invalid Elements will be rendered but not animated.

Animatable Elements

Only ReactElement that are able to receives a ref and have implemented specific methods and properties will be animated. The required ref properties are:

  • animate
  • getBoundingClientRect
  • getAnimations
  • removeAttribute
  • parentElement

easing?: string = "ease-in-out"

The easing of the moving animation.

duration?: number = 500

The duration of the moving animation in milliseconds.

normalizeKeys?: boolean = false

Whether or not to normalize keys. If set to true, the component will flatten the children array and check for uniquely defined keys. If set to false (default), the component allows for duplicate keys if its under different fragment.

By default, this configuration is allowed:

<AnimateChildren>
  {arr1.map((el,i) => <div key={i}>{el}</div>)}
  <>
    {arr1.map((el,i) => <div key={i}>{el}</div>)}
  </>
</AnimateChildren> // ✅ Legal, No errors

If set to true, the above configuration will throw an error.

delayDeletion?: number = 500

The delay before the deletion of the child. This is useful when you want to animate the child before it is removed from the DOM.

useAbsolutePositionOnDelete?: boolean = false

Whether or not to use absolute position on deleted elements. If set to true, the component will use absolute position to animate the deleted child.

Recommended:
Set to true if the width of the child is fixed.

stagger?: number

The stagger of the moving animation in milliseconds. The animation delay will be skipped if the animation is interrupted.

strategy?: "interrupt" | "continuous" | "reset" = continuous

The strategy to use when taking a snapshot of the child's position. The default is continuous, which uses the offsetLeft and offsetTop property of the child. If set to interrupt, the component will use the getBoundingClientRect method to take a snapshot of the child's position.

disableAnimationReconciliation?: boolean

Whether or not to disable animation reconciliation. If set to true, the component will not reconcile CSS animations.

Recommended:
Set to false if animating a large number of children.

disableScaleAnimation?: boolean

Whether or not to disable scale animation. If set to true, the component will not scale the child during animating the reorder.

disableParentAnimation?: boolean

Whether or not to disable parent animation. If set to true, the component will not animate the parent.

Back to top ↑⭐️ Star on GitHub →