Animated Group
A wrapper that adds animated transitions to a group of child elements. It's perfect for creating staggered animations for lists, grids, or any collection of components.
Examples
Animated Group with preset
Images are from cosmos - Impressionisme
Animated Group with custom variants
AnimatedGroup with custom variants
Code
'use client';
import { ReactNode } from 'react';
import { motion, Variants } from 'motion/react';
import React from 'react';
type PresetType =
| 'fade'
| 'slide'
| 'scale'
| 'blur'
| 'blur-slide'
| 'zoom'
| 'flip'
| 'bounce'
| 'rotate'
| 'swing';
type AnimatedGroupProps = {
children: ReactNode;
className?: string;
variants?: {
container?: Variants;
item?: Variants;
};
preset?: PresetType;
};
const defaultContainerVariants: Variants = {
hidden: { opacity: 0 },
visible: {
opacity: 1,
transition: {
staggerChildren: 0.1,
},
},
};
const defaultItemVariants: Variants = {
hidden: { opacity: 0 },
visible: { opacity: 1 },
};
const presetVariants: Record<
PresetType,
{ container: Variants; item: Variants }
> = {
fade: {
container: defaultContainerVariants,
item: {
hidden: { opacity: 0 },
visible: { opacity: 1 },
},
},
slide: {
container: defaultContainerVariants,
item: {
hidden: { opacity: 0, y: 20 },
visible: { opacity: 1, y: 0 },
},
},
scale: {
container: defaultContainerVariants,
item: {
hidden: { opacity: 0, scale: 0.8 },
visible: { opacity: 1, scale: 1 },
},
},
blur: {
container: defaultContainerVariants,
item: {
hidden: { opacity: 0, filter: 'blur(4px)' },
visible: { opacity: 1, filter: 'blur(0px)' },
},
},
'blur-slide': {
container: defaultContainerVariants,
item: {
hidden: { opacity: 0, filter: 'blur(4px)', y: 20 },
visible: { opacity: 1, filter: 'blur(0px)', y: 0 },
},
},
zoom: {
container: defaultContainerVariants,
item: {
hidden: { opacity: 0, scale: 0.5 },
visible: {
opacity: 1,
scale: 1,
transition: { type: 'spring', stiffness: 300, damping: 20 },
},
},
},
flip: {
container: defaultContainerVariants,
item: {
hidden: { opacity: 0, rotateX: -90 },
visible: {
opacity: 1,
rotateX: 0,
transition: { type: 'spring', stiffness: 300, damping: 20 },
},
},
},
bounce: {
container: defaultContainerVariants,
item: {
hidden: { opacity: 0, y: -50 },
visible: {
opacity: 1,
y: 0,
transition: { type: 'spring', stiffness: 400, damping: 10 },
},
},
},
rotate: {
container: defaultContainerVariants,
item: {
hidden: { opacity: 0, rotate: -180 },
visible: {
opacity: 1,
rotate: 0,
transition: { type: 'spring', stiffness: 200, damping: 15 },
},
},
},
swing: {
container: defaultContainerVariants,
item: {
hidden: { opacity: 0, rotate: -10 },
visible: {
opacity: 1,
rotate: 0,
transition: { type: 'spring', stiffness: 300, damping: 8 },
},
},
},
};
function AnimatedGroup({
children,
className,
variants,
preset,
}: AnimatedGroupProps) {
const selectedVariants = preset
? presetVariants[preset]
: { container: defaultContainerVariants, item: defaultItemVariants };
const containerVariants = variants?.container || selectedVariants.container;
const itemVariants = variants?.item || selectedVariants.item;
return (
<motion.div
initial='hidden'
animate='visible'
variants={containerVariants}
className={className}
>
{React.Children.map(children, (child, index) => (
<motion.div key={index} variants={itemVariants}>
{child}
</motion.div>
))}
</motion.div>
);
}
export { AnimatedGroup };
Please add:
Component API
AnimatedGroup
Prop | Type | Default | Description |
---|---|---|---|
children | ReactNode | The child elements to be animated. | |
className | string | undefined | Optional CSS class for styling the component. |
variants | { container?: Variants; item?: Variants; } | undefined | Custom variants for container and item animations. |
preset | 'fade' | 'slide' | 'scale' | 'blur' | 'blur-slide' | undefined | Preset animations to apply to the group of elements. |