HomeH
ProjectsP
BlogB
ContactC

Connect

  • @irfaan_ansari1
  • @irfaan.dev
  • /irfaan-ansari
  • /irfaan-ansari
Designed and developed byIrfaan AnsariIrfaan AnsariIrfaan Ansari
Visitor#11574
New Delhi, IndiaSitemap
BackB

Hand Wave Animation in React Using Motion and Tailwind CSS

Next.jsMotionTailwind CSSFrontendAnimations
5mo ago8 min read

Thoughtful micro-interactions can transform a static interface into something more welcoming and human. In this project, I built a hand-wave animation component using React, Motion, and Tailwind CSS to demonstrate how subtle motion can improve user experience without overwhelming the design.

In this post, we’ll create a reusable animated SVG component using Motion to handle animation states and transitions.

Objective

  • Animate a standard SVG icon using Motion
  • Keep the animation smooth and natural
  • Make the component reusable across different parts of an application

Tech Stack

  • Next.js App Router
  • Motion for animation control
  • Tailwind CSS for styling and sizing
  • SVG for scalable, crisp visuals

Component Structure

The animation is applied directly to the SVG itself using motion.svg.

<motion.svg
  fill="none"
  viewBox="0 0 16 16"
  className={cn("size-4", className)}
>

Instead of using a regular SVG element with additional CSS keyframe animations, this component uses motion.svg, which provides built-in animation capabilities such as initial, animate, and transition props.

Styling and Reusability

The SVG uses currentColor, allowing it to inherit text color from its parent. Sizing is handled via Tailwind size-4 by default, and the optional className prop allows full customization.

Wave Animation Logic

The waving motion is created using a sequence of rotation values combined with subtle scaling:

animate={{
  rotate: [0, 20, -10, 20, -5, 0],
  scale: [1, 1.2, 1.2, 1],
}}

Instead of a single rotation, multiple angles are used to simulate a natural hand wave. The slight scale increase adds a sense of energy without being distracting.

Timing and Loop Behavior

transition={{
  duration: 1,
  repeat: Infinity,
  times: [0, 0.2, 0.8, 1],
  repeatDelay: 2,
  ease: "easeInOut",
}}
  • 1 second per wave
  • Infinite looping
  • 2 second pause between waves
  • Smooth easing for a natural feel

This timing ensures the animation feels friendly and intentional, not repetitive or noisy.

Live Demo: How It Feels in the UI

Here’s the complete code

"use client";
import { cn } from "@/lib/utils";
import { motion } from "motion/react";

type WaveIconProps = {
  className?: string;
};
const WaveIcon = ({ className }: WaveIconProps) => {
  return (
    <motion.svg
      fill="none"
      viewBox="0 0 16 16"
      initial={{ scale: 1 }}
      animate={{ rotate: [0, 20, -10, 20, -5, 0], scale: [1, 1.2, 1.2, 1] }}
      transition={{
        duration: 1,
        repeat: Infinity,
        times: [0, 0.2, 0.8, 1],
        repeatDelay: 2,
        ease: "easeInOut",
      }}
      className={cn("size-4 inline-flex", className)}
    >
      <g stroke="currentColor" strokeWidth="1.33333">
        <path d="m10.6812 6.48941-2.97055-5.15608-1.14342.66152c-.63148.36535-.84784 1.17452-.48326 1.80732m4.59723 2.68724.9902 1.71872-.5719.33086c-.9472.548-1.27179 1.76181-.7249 2.71101l.3301.5729m-.0235-5.33349c-.3646-.63281-.1482-1.44198.4833-1.80732l1.1433-.66153 1.6504 2.8645c1.4584 2.53127.5929 5.76794-1.933 7.22934l-.5716.3307m-5.36963-10.64293-1.32027-2.29159-1.14339.66153c-.63148.36535-.84784 1.17451-.48325 1.80732m2.94691-.17726 2.31048 4.01029m-5.25739-3.83303-1.14339.66152c-.63148.36535-.84784 1.17452-.48325 1.80732l4.73492 8.21843m-3.10828-10.68727 2.97061 5.1561" />
        <path d="m.666687 11.3333c0 1.0609.421423 2.0783 1.171573 2.8284.75015.7502 1.76756 1.1716 2.82843 1.1716" />
        <path d="m15.3333 4.66667c0-1.06086-.4214-2.07828-1.1716-2.82842-.7501-.75015-1.7675-1.171578-2.8284-1.171578" />
      </g>
    </motion.svg>
  );
};

export default WaveIcon;

Notice the use client directive at the top of the file. This is necessary because Motion uses browser APIs that are unavailable in server components.

Final Thoughts

This hand-wave animation is a small but intentional detail designed to add personality without distraction. By combining Motion’s animation control with Tailwind’s styling flexibility, the result is a clean, expressive UI component suitable for real-world production use.

Micro-interactions like this can make interfaces feel more approachable—and often, that’s what users remember most.