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 tooverflow: auto
, it may cause scrolling issues. It is recommended to set the parent tooverflow: hidden
oroverflow: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 toReactNode
or changingmoduleResolution
intsconfig.json
to other values thannode
orclassic
.
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.