I’ve been using the same animation pattern in my projects for a while now to animate elements onto the screen. In its simplest form, you would have an element styled with the opacity of zero, then change the styling to have an opacity of one with a CSS transition of a second. We can build on top of that by adding other properties that transition, changing the duration, adding a delay, or setting custom easing. is a reusable React component that I’ve made to drop in whenever I want to quickly add some animation effects to my projects. A simple utility component, it combines CSS Animation with Tailwind classes to create fluid, eye-catching animations with minimal effort. <AnimateIn/> Let’s take a look at how it is used. After importing the component, define and states with Tailwind classes. Wrap the target element within to see the animation come to life. from to <AnimateIn/> import AnimateIn from '../animation/AnimateIn'; <AnimateIn from="opacity-0 scale-90" to="opacity-100 scale-100" duration={500} > <YourComponent /> </AnimateIn> Here’s a slightly more complex example that uses more properties to animate in a headline and subtitle. import AnimateIn from '../animation/AnimateIn'; <header> <AnimateIn as="h1" from="opacity-0 translate-y-32" to="opacity-100 translate-y-0" delay={500} duration={300} className="text-4xl" style={{transitionTimingFunction:"cubic-bezier(0.25, 0.4, 0.55, 1.4)"}} > My Big Headline </AnimateIn> <AnimateIn as="h2" from="opacity-0 scale-0" to="opacity-100 scale-100" delay={800} duration={500} className="text-lg" > This is a subtitle below the headline </AnimateIn> </header> In the headline example, is used to create a sliding effect combined with a fade-in. Here’s how each property contributes to the animation: <AnimateIn/> property: By setting , we tell AnimateIn to render the animation as an element. as as="h1" <h1> and properties: The property starts the headline off-screen ( , moving it 32 units down) and invisible ( ). The property then brings the headline to its final position (back to ) and makes it fully visible ( ). from to from translate-y-32 opacity-0 to translate-y-0 opacity-100 property: The animation is set to begin immediately with no delay and runs for a quick 300ms. duration property: The applies Tailwind's utility class to set the font size, making the headline prominently stand out. className className="text-4xl" property: The custom ( ) adds a unique ease to the animation, giving it a bounce-like effect. style transitionTimingFunction cubic-bezier(0.25, 0.4, 0.55, 1.4) The subtitle uses a different set of animations to complement the headline, creating a cohesive visual flow. property: Here, renders the component as an element, suitable for a subtitle. as as="h2" <h2> and properties: The subtitle starts scaled down to zero ( ) and invisible ( ), then scales up to its natural size ( ) and becomes fully visible ( ). This scaling effect, paired with a fade-in, adds depth to the animation. from to scale-0 opacity-0 scale-100 opacity-100 and properties: The subtitle also starts after an 800ms delay so that it begins after the headline has fully animated. This staggered approach ensures that each element gets its moment of focus. delay duration property: The sets the subtitle's font size, making it smaller than the headline but still significant. className className="text-lg" To better understand what’s happening, let’s look at the source code for : <AnimateIn/> on Github uses a hook to initialize the animation state with the property, which should be one or more Tailwind utility classes, setting the stage for the animation’s starting point before any animation takes place. <AnimateIn/> useState from The first hook in the component is for respecting user preferences for reduced motion. By listening to the media query, the animation behavior is based on the user’s system settings. If reduced motion is preferred, the animation is skipped entirely, directly setting the animation state to the property, allowing for an accessible experience. useEffect (prefers-reduced-motion: reduce) to The second hook is where the animation logic resides. If the user has not indicated a preference for reduced motion, the component sets a timer that changes the animation state from the initial value to the final value after the specified delay. This transition creates the visual effect of animation. useEffect from to The cleanup function of this hook (the return statement) clears the timer, preventing potential memory leaks such as if the component unmounts before the animation is completed. The function call is the component’s rendering mechanism. It dynamically creates an HTML element based on the prop, allowing the use of the component across different HTML elements. The is constructed using the function as , which combines Tailwind’s utility classes, the custom passed as a prop, and the current animation state. This dynamic class assignment is what applies the desired styles and transitions to the element. React.createElement as className cn popularized by shadcn className Additionally, there is a attribute that can be passed in to directly set styling properties on the animation container. The is set based on the prop, but it intelligently switches to if the user prefers reduced motion, effectively disabling the animation while maintaining the component’s functionality. style transitionDuration duration 0ms If you’d like to use in your own project and it already uses , then you already have everything you need, just and add it to your components. <AnimateIn/> shadcn download AnimateIn.tsx Otherwise, you’ll want to as well as the for merging tailwind classes. install Tailwind mxcn helpful utility Like shadcn, <AnimateIn/> is meant to be a reusable component that you can copy and paste into your apps and customize to your needs. The code is yours. Also, I’ve put together a nice demo page for playing around with creating different animations with at . <AnimateIn/> animate-in.vercel.app Also published here