Installation
Install the following dependencies:
pnpm add motion
Create a file at components/motions/animated-group.tsx
and paste the given
code.
"use client";
import { JSX, ReactNode } from "react";
import { motion, Variants } from "motion/react";
import React from "react";
export type PresetType =
| "fade"
| "slide"
| "scale"
| "blur"
| "blur-slide"
| "zoom"
| "flip"
| "bounce"
| "rotate"
| "swing";
export type AnimatedGroupProps = {
children: ReactNode;
className?: string;
variants?: {
container?: Variants;
item?: Variants;
};
preset?: PresetType;
as?: React.ElementType;
asChild?: React.ElementType;
};
const defaultContainerVariants: Variants = {
visible: {
transition: {
staggerChildren: 0.1,
},
},
};
const defaultItemVariants: Variants = {
hidden: { opacity: 0 },
visible: { opacity: 1 },
};
const presetVariants: Record<PresetType, Variants> = {
fade: {},
slide: {
hidden: { y: 20 },
visible: { y: 0 },
},
scale: {
hidden: { scale: 0.8 },
visible: { scale: 1 },
},
blur: {
hidden: { filter: "blur(4px)" },
visible: { filter: "blur(0px)" },
},
"blur-slide": {
hidden: { filter: "blur(4px)", y: 20 },
visible: { filter: "blur(0px)", y: 0 },
},
zoom: {
hidden: { scale: 0.5 },
visible: {
scale: 1,
transition: { type: "spring", stiffness: 300, damping: 20 },
},
},
flip: {
hidden: { rotateX: -90 },
visible: {
rotateX: 0,
transition: { type: "spring", stiffness: 300, damping: 20 },
},
},
bounce: {
hidden: { y: -50 },
visible: {
y: 0,
transition: { type: "spring", stiffness: 400, damping: 10 },
},
},
rotate: {
hidden: { rotate: -180 },
visible: {
rotate: 0,
transition: { type: "spring", stiffness: 200, damping: 15 },
},
},
swing: {
hidden: { rotate: -10 },
visible: {
rotate: 0,
transition: { type: "spring", stiffness: 300, damping: 8 },
},
},
};
const addDefaultVariants = (variants: Variants) => ({
hidden: { ...defaultItemVariants.hidden, ...variants.hidden },
visible: { ...defaultItemVariants.visible, ...variants.visible },
});
function AnimatedGroup({
children,
className,
variants,
preset,
as = "div",
asChild = "div",
}: AnimatedGroupProps) {
const selectedVariants = {
item: addDefaultVariants(preset ? presetVariants[preset] : {}),
container: addDefaultVariants(defaultContainerVariants),
};
const containerVariants = variants?.container || selectedVariants.container;
const itemVariants = variants?.item || selectedVariants.item;
const MotionComponent = motion.create(as as keyof JSX.IntrinsicElements);
const MotionChild = motion.create(asChild as keyof JSX.IntrinsicElements);
return (
<MotionComponent
initial="hidden"
animate="visible"
variants={containerVariants}
className={className}
>
{React.Children.map(children, (child, index) => (
<MotionChild key={index} variants={itemVariants}>
{child}
</MotionChild>
))}
</MotionComponent>
);
}
export { AnimatedGroup };