If you're working with animations in Next.js, you've probably found yourself writing the same Motion code over and over again. Let's solve that by creating a simple, reusable MotionDiv
component that will save you time and keep your animations consistent.
What We're Building
We're going to create a wrapper component around Motion's motion.div
that provides better TypeScript support and integrates seamlessly with our existing utilities. Here's the complete component:
'use client';
import { motion, HTMLMotionProps } from 'framer-motion';
import { cn } from '@/lib/utils';
interface MotionDivProps extends HTMLMotionProps<'div'> {
className?: string;
}
const MotionDiv = ({ children, className, ...motionProps }: MotionDivProps) => {
return (
<motion.div className={cn(className)} {...motionProps}>
{children}
</motion.div>
);
};
export default MotionDiv;
Step-by-Step Setup
1. Install Dependencies
First, make sure you have Motion installed in your Next.js project:
npm install motion
2. Create the Component
Create a new file components/ui/MotionDiv.tsx
(or wherever you keep your components) and add the code above.
3. The 'use client' Directive
Since we're using Next.js with the App Router, we need the' use client' directive. This tells Next.js that this component should run on the client side.
4. TypeScript Interface
The MotionDivProps
interface extends HTMLMotionProps<'div'>
, which means our component gets all the props that motion.div accepts — including standard div props like className, animation props, and event handlers.
How to Use It
Once you've created the component, using it is straightforward:
Basic Fade-in Animation
<MotionDiv
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ duration: 0.5 }}
className="p-4 bg-white rounded-lg shadow-lg"
>
<h2>This content fades in</h2>
<p>Much cleaner than writing motion.div everywhere!</p>
</MotionDiv>
Slide Animation
<MotionDiv
initial={{ x: -50, opacity: 0 }}
animate={{ x: 0, opacity: 1 }}
className="notification-banner"
>
New notification!
</MotionDiv>
Hover Effects
<MotionDiv
whileHover={{ scale: 1.02 }}
whileTap={{ scale: 0.98 }}
className="card cursor-pointer"
>
Interactive card content
</MotionDiv>
Why Make It Reusable?
1. Less Repetitive Code
Instead of importing motion
and writing motion.div
throughout your app, you just import and use MotionDiv
. It might seem small, but it adds up across a large project.
2. Consistent Animations
When your team uses the same component, you naturally end up with more consistent animation patterns. No more wondering why some elements animate differently than others.
3. Better TypeScript Experience
You get full TypeScript support with autocompletion for all Framer Motion props. If you make a typo in an animation property, TypeScript will catch it.
4. Easy to Extend
Need to add default animations or custom presets later? You can modify this one component instead of hunting down every motion.div
in your codebase.
5. Utility Integration
The cn
function (usually from libraries like clsx
or custom utility functions) handles className merging and conditional classes. This works great with Tailwind CSS or any CSS framework.
Real-World Example
Here's how you might use it in a typical Next.js 15 page:
// app/page.tsx
import MotionDiv from '@/components/ui/MotionDiv';
export default function HomePage() {
return (
<main className="container mx-auto px-4">
<MotionDiv
initial={{ y: 20, opacity: 0 }}
animate={{ y: 0, opacity: 1 }}
transition={{ duration: 0.6 }}
className="text-center py-16"
>
<h1 className="text-4xl font-bold mb-4">Welcome to Our Site</h1>
<p className="text-lg text-gray-600">
This hero section animates in smoothly
</p>
</MotionDiv>
<MotionDiv
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ delay: 0.3, duration: 0.6 }}
className="grid grid-cols-1 md:grid-cols-3 gap-6 py-12"
>
{/* Your content here */}
</MotionDiv>
</main>
);
}
Taking It Further
Once you're comfortable with the basic MotionDiv
, you can extend it with features like:
- Animation presets: Add common animation patterns as props
- Default values: Set up sensible defaults for common use cases
- Conditional animations: Toggle animations based on user preferences
- Stagger support: Built-in support for staggered animations
Wrapping Up
Creating a reusable MotionDiv
component is a simple way to make your Next.js animations more maintainable and consistent. It takes just a few minutes to set up, but you'll appreciate the cleaner code and better developer experience every time you add animations to your app.
Top comments (0)
Some comments may only be visible to logged-in visitors. Sign in to view all comments.