GlanceGlance
Back to Blog
Framer MotionApril 1, 202611 min read

Awwwards-Level Hover Effects with Framer Motion in React (2026)

Build magnetic cursors, reveal-on-hover cards, staggered menu animations, and tilt effects using Framer Motion. Each example includes live preview and full copy-paste source code.

Share:

Hover interactions are the micro-details that separate a $500 template from a $50,000 agency build. This guide walks through 7 Awwwards-level hover effects you can build with Framer Motion in React — each with code you can copy directly into your project.

Framer Motion is the dominant animation library in the React ecosystem. Its declarative API — whileHover, whileTap, spring physics — makes complex interactions trivial to implement and maintain.

All effects below are on Glance → Preview each hover animation live in your browser, then download the complete source code. Browse the library — starts at $3.99.

1. Magnetic Button Effect

The magnetic effect makes buttons pull toward the cursor as it hovers nearby. It's the signature interaction on sites like Awwwards itself. The effect uses Framer Motion's useMotionValue and useSpring to create physically realistic movement.

"use client"
import { useRef } from "react"
import { motion, useMotionValue, useSpring } from "framer-motion"

export function MagneticButton({ children }: { children: React.ReactNode }) {
  const ref = useRef<HTMLDivElement>(null)
  const x = useMotionValue(0)
  const y = useMotionValue(0)
  const springX = useSpring(x, { stiffness: 150, damping: 15 })
  const springY = useSpring(y, { stiffness: 150, damping: 15 })

  const handleMouseMove = (e: React.MouseEvent) => {
    const rect = ref.current?.getBoundingClientRect()
    if (!rect) return
    const centerX = rect.left + rect.width / 2
    const centerY = rect.top + rect.height / 2
    x.set((e.clientX - centerX) * 0.3)
    y.set((e.clientY - centerY) * 0.3)
  }

  const handleMouseLeave = () => {
    x.set(0)
    y.set(0)
  }

  return (
    <motion.div
      ref={ref}
      style={{ x: springX, y: springY }}
      onMouseMove={handleMouseMove}
      onMouseLeave={handleMouseLeave}
      className="inline-block"
    >
      {children}
    </motion.div>
  )
}

The 0.3 multiplier controls pull strength — increase it for a more dramatic effect, decrease for subtlety.

2. Card Reveal with Clip-Path

On hover, a color or image layer reveals from a specific direction using clip-path animation. This creates a premium portfolio card effect that immediately catches the eye.

<motion.div className="relative overflow-hidden rounded-2xl">
  <motion.div
    className="absolute inset-0 bg-black z-10"
    initial={{ clipPath: "inset(0 100% 0 0)" }}
    whileHover={{ clipPath: "inset(0 0% 0 0)" }}
    transition={{ duration: 0.5, ease: [0.77, 0, 0.175, 1] }}
  />
  <img src="/project.jpg" className="w-full" />
  <motion.span
    className="absolute bottom-6 left-6 z-20 text-white font-bold text-xl"
    initial={{ opacity: 0, y: 10 }}
    whileHover={{ opacity: 1, y: 0 }}
    transition={{ delay: 0.2 }}
  >
    Project Title
  </motion.span>
</motion.div>

The cubic bezier [0.77, 0, 0.175, 1] mimics the signature easing used by high-end agencies. It accelerates quickly and decelerates smoothly — what motion designers call an "expo" ease.

3. Staggered Menu Item Reveal

When a navigation menu opens, items that stagger in one by one create a much more polished feel than everything appearing at once. Framer Motion's staggerChildren makes this a one-line configuration.

const containerVariants = {
  hidden: {},
  visible: {
    transition: { staggerChildren: 0.08, delayChildren: 0.1 }
  }
}

const itemVariants = {
  hidden: { opacity: 0, y: 20, filter: "blur(4px)" },
  visible: {
    opacity: 1, y: 0, filter: "blur(0px)",
    transition: { duration: 0.5, ease: [0.25, 0.46, 0.45, 0.94] }
  }
}

<motion.ul variants={containerVariants} initial="hidden" animate="visible">
  {menuItems.map(item => (
    <motion.li key={item} variants={itemVariants}>{item}</motion.li>
  ))}
</motion.ul>

The filter: "blur(4px)" on the hidden state adds a subtle de-focus effect during the entrance — a small detail with big visual impact.

4. 3D Tilt Card

Tilt effects give flat cards a three-dimensional feel by rotating them based on cursor position. This uses Framer Motion's useMotionValue to track mouse position and useTransform to map it to rotation values.

const x = useMotionValue(0.5)
const y = useMotionValue(0.5)
const rotateX = useTransform(y, [0, 1], [10, -10])
const rotateY = useTransform(x, [0, 1], [-10, 10])

const handleMouseMove = (e: React.MouseEvent<HTMLDivElement>) => {
  const rect = e.currentTarget.getBoundingClientRect()
  x.set((e.clientX - rect.left) / rect.width)
  y.set((e.clientY - rect.top) / rect.height)
}

<motion.div
  onMouseMove={handleMouseMove}
  onMouseLeave={() => { x.set(0.5); y.set(0.5) }}
  style={{ rotateX, rotateY, transformPerspective: 800 }}
  className="rounded-2xl bg-white p-8 shadow-lg"
>
  Card Content
</motion.div>

5. Underline Slide Effect

The sliding underline — where a line grows from left to right on hover — is the most common navigation hover effect on premium websites. With Framer Motion, it's a single scaleX animation with transformOrigin: "left".

<motion.a href="#" className="relative inline-block group">
  Navigation Link
  <motion.span
    className="absolute bottom-0 left-0 w-full h-[2px] bg-black origin-left"
    initial={{ scaleX: 0 }}
    whileHover={{ scaleX: 1 }}
    transition={{ duration: 0.3, ease: "easeInOut" }}
  />
</motion.a>

6. Image Zoom with Overlay

A subtle zoom on the image combined with a darkening overlay and text that fades in is the standard portfolio hover pattern. The key is keeping the zoom subtle (1.05–1.1) and using overflow-hidden on the container so the scaled image doesn't break layout.

<motion.div className="relative overflow-hidden rounded-xl cursor-pointer" whileHover="hovered">
  <motion.img
    src="/image.jpg"
    variants={{ hovered: { scale: 1.08 } }}
    transition={{ duration: 0.6, ease: "easeOut" }}
    className="w-full object-cover"
  />
  <motion.div
    className="absolute inset-0 bg-black/50 flex items-end p-6"
    variants={{ hovered: { opacity: 1 } }}
    initial={{ opacity: 0 }}
    transition={{ duration: 0.3 }}
  >
    <h3 className="text-white font-bold text-lg">Project Name</h3>
  </motion.div>
</motion.div>

7. Morphing Button

A button that morphs shape on hover — expanding width, changing border-radius, or revealing an icon — adds personality to CTAs. Framer Motion's layout prop handles smooth size transitions automatically.

const [isHovered, setIsHovered] = useState(false)

<motion.button
  onMouseEnter={() => setIsHovered(true)}
  onMouseLeave={() => setIsHovered(false)}
  animate={{
    width: isHovered ? 200 : 150,
    borderRadius: isHovered ? 12 : 50,
  }}
  transition={{ type: "spring", stiffness: 400, damping: 30 }}
  className="h-12 bg-black text-white font-medium"
>
  <motion.span layout>
    {isHovered ? "Let's Go →" : "Explore"}
  </motion.span>
</motion.button>

Performance Tips for Hover Effects

  1. Stick to transform and opacity. Animating these properties uses the GPU compositor and won't trigger layout recalculation.
  2. Use spring physics. Springs feel more natural than linear or ease-in-out transitions and Framer Motion optimizes them internally.
  3. Respect prefers-reduced-motion. Wrap animations in a check: const prefersReduced = useReducedMotion() and disable hover effects for users who set this OS preference.
  4. Avoid hover on mobile. Touch devices don't have a hover state. Use media queries or Framer Motion's whileTap as a fallback.

Get All These Effects Ready-Made

Every effect in this article (and 120+ more) is available on Glance as a complete, runnable component. Preview any animation live, download the source code, and ship it in your next project. No npm packages. No dependency lock-in. Just clean, production-ready code.

Starter access starts at $3.99 for 50+ animations including hover effects, scroll animations, and text reveals. Pro at $19 unlocks all 130+ animations plus every future addition.

Browse Hover Effects on Glance →

Frequently Asked Questions

What is Framer Motion?

Framer Motion is a production-ready animation library for React. It provides declarative animations through motion components (like motion.div), gesture recognition (hover, tap, drag), layout animations, and AnimatePresence for mount/unmount transitions. It's the most popular React animation library with over 25,000 GitHub stars and is used by Vercel, Stripe, and many Awwwards-winning sites.

How do I create a hover animation with Framer Motion?

Use the whileHover prop on any motion component. For example: <motion.div whileHover={{ scale: 1.05 }}>. Framer Motion handles the enter and exit transitions automatically with spring physics by default. You can customize timing with the transition prop: <motion.div whileHover={{ scale: 1.05 }} transition={{ type: 'spring', stiffness: 300, damping: 20 }}>.

Is Framer Motion good for performance?

Yes. Framer Motion uses hardware-accelerated transforms by default and batches DOM reads/writes. For most hover effects, it adds negligible overhead. However, animating many elements simultaneously or using layout animations on large lists can cause frame drops. For those cases, consider using CSS transitions or GSAP instead.

Can I use Framer Motion with Next.js App Router?

Yes, but motion components must be used in Client Components (files with 'use client' directive). Server Components cannot use Framer Motion directly. The common pattern is to create a client wrapper component that adds the animation, and import it in your Server Component page.

What is a magnetic cursor effect?

A magnetic cursor effect is when interactive elements (buttons, links, cards) subtly move toward the user's cursor as it approaches. This creates a feeling of physicality and interactivity. It's implemented by tracking mouse position relative to the element center and applying a transform. Framer Motion's useMotionValue and useTransform hooks make this smooth and performant.

Framer Motion vs CSS hover effects — which should I use?

Use CSS for simple state changes (color, background, scale). Use Framer Motion when you need spring physics, staggered children animations, gesture sequences, or animations that coordinate across multiple elements. Framer Motion also handles reduced-motion preferences automatically and provides better control over timing curves than CSS transitions.

Stop building animations from scratch

130+ production-ready animations for React, Next.js, and Vanilla JS. Preview live, grab the code, ship it. Starts at $3.99.

Browse the Animation Library →