---
title: "Framer Button Hover Effects (Copy-Paste Guide)"
description: "Six real Framer button hover effects with ready-to-use code overrides — scale, fill sweep, magnetic pull, icon slide, gradient border, and more."
canonical_url: "https://framerhub.io/blog/button-hover-effects-framer"
last_updated: "2026-11-27T00:00:00.000Z"
---

Generic CSS hover-effect roundups don't translate directly to Framer — you're not writing a stylesheet, you're using property panel variants or code overrides inside Framer's own component model. Here are six real button hover effects, built the Framer way, with working code where a code override is the right tool.

## Before Code: What Framer's Native Tools Handle

Not every hover effect needs a code override. Framer's built-in variants and interaction settings handle:

- Color and background changes on hover
- Simple scale or opacity shifts
- Basic shadow changes

Set these up by creating a hover variant on your button component and adjusting the properties you want to change — no code required. Reach for a code override when you need something a simple property-change variant can't express: spring physics, multi-step sequences, or effects that respond to cursor position rather than a binary hover on/off state.

## Effect 1: Scale + Shadow Lift

The most common, most broadly effective button hover — a slight scale-up paired with a shadow that suggests the button lifting toward the cursor.

```jsx
import { motion } from "motion/react"

export function ScaleLift(Component): ComponentType {
  return (props) => (
    <motion.div
      whileHover={{ scale: 1.04, boxShadow: "0px 8px 20px rgba(0,0,0,0.15)" }}
      whileTap={{ scale: 0.98 }}
      transition={{ duration: 0.2, ease: "easeOut" }}
    >
      <Component {...props} />
    </motion.div>
  )
}
```

This works well as a default across most buttons on a site because it's subtle enough not to distract while still confirming interactivity clearly.

## Effect 2: Fill Sweep

A background color that sweeps in from one side on hover, rather than an instant color change — a classic effect that reads as more polished than a flat color swap.

```jsx
import { motion } from "motion/react"

export function FillSweep(Component): ComponentType {
  return (props) => (
    <motion.div style={{ position: "relative", overflow: "hidden" }}>
      <motion.div
        style={{
          position: "absolute",
          inset: 0,
          background: "var(--accent-color)",
          originX: 0,
        }}
        initial={{ scaleX: 0 }}
        whileHover={{ scaleX: 1 }}
        transition={{ duration: 0.3, ease: "easeInOut" }}
      />
      <Component {...props} />
    </motion.div>
  )
}
```

Keep the text color set to work against both the resting and swept-in background colors, or add a second layer that crossfades the text color in sync with the sweep — otherwise you risk low-contrast text mid-transition.

## Effect 3: Magnetic Pull

The button subtly follows the cursor within a small radius before it's even clicked — a more playful, attention-grabbing effect best reserved for a hero CTA rather than every button on the page.

```jsx
import { motion, useMotionValue, useSpring } from "motion/react"

export function MagneticButton(Component): ComponentType {
  return (props) => {
    const x = useMotionValue(0)
    const y = useMotionValue(0)
    const springX = useSpring(x, { stiffness: 150, damping: 15 })
    const springY = useSpring(y, { stiffness: 150, damping: 15 })

    function handleMouseMove(e) {
      const rect = e.currentTarget.getBoundingClientRect()
      x.set((e.clientX - rect.left - rect.width / 2) * 0.3)
      y.set((e.clientY - rect.top - rect.height / 2) * 0.3)
    }

    function handleMouseLeave() {
      x.set(0)
      y.set(0)
    }

    return (
      <motion.div
        style={{ x: springX, y: springY }}
        onMouseMove={handleMouseMove}
        onMouseLeave={handleMouseLeave}
      >
        <Component {...props} />
      </motion.div>
    )
  }
}
```

This effect is genuinely fun in a hero section and genuinely annoying on every button in a long list — use it sparingly, on one or two high-visibility CTAs per page at most.

## Effect 4: Icon Slide

A small icon (usually an arrow) slides in the direction of travel on hover — a subtle directional cue that works especially well on "learn more" or "next" style links and buttons.

```jsx
import { motion } from "motion/react"

export function IconSlide(Component): ComponentType {
  return (props) => (
    <motion.div
      style={{ display: "flex", alignItems: "center", gap: 8 }}
      initial="rest"
      whileHover="hover"
    >
      <Component {...props} />
      <motion.span
        variants={{ rest: { x: 0 }, hover: { x: 4 } }}
        transition={{ duration: 0.15 }}
      >
        →
      </motion.span>
    </motion.div>
  )
}
```

Pair this with the fill sweep or a simple color change on the text itself for a more complete effect without overdoing the motion.

## Effect 5: Gradient Border Sweep

A gradient border that animates around the button's edge on hover — a distinctive effect that works well for a brand with a strong gradient identity, but easy to overdo if used everywhere.

```jsx
import { motion } from "motion/react"

export function GradientBorder(Component): ComponentType {
  return (props) => (
    <motion.div
      style={{
        position: "relative",
        borderRadius: 12,
        padding: 2,
        background: "linear-gradient(90deg, var(--accent-1), var(--accent-2))",
        backgroundSize: "200% 100%",
      }}
      initial={{ backgroundPosition: "0% 0%" }}
      whileHover={{ backgroundPosition: "100% 0%" }}
      transition={{ duration: 0.6, ease: "easeInOut" }}
    >
      <Component {...props} />
    </motion.div>
  )
}
```

Reserve this for a primary CTA where the extra visual weight is intentional — applied to every button on a page, it competes with itself for attention.

## Effect 6: Underline Draw

A minimal, text-focused effect well-suited to link-style buttons rather than filled buttons — an underline that draws in from one side rather than appearing instantly.

```jsx
import { motion } from "motion/react"

export function UnderlineDraw(Component): ComponentType {
  return (props) => (
    <motion.div style={{ position: "relative", display: "inline-block" }}>
      <Component {...props} />
      <motion.div
        style={{
          position: "absolute",
          bottom: -2,
          left: 0,
          height: 2,
          background: "currentColor",
          originX: 0,
        }}
        initial={{ scaleX: 0 }}
        whileHover={{ scaleX: 1 }}
        transition={{ duration: 0.25 }}
      />
    </motion.div>
  )
}
```

This is the effect to reach for on text links and secondary navigation rather than primary CTA buttons, where a filled effect (scale, fill sweep) usually communicates "click me" more clearly.

## Common Mistakes That Undermine a Good Hover Effect

A technically well-built hover effect can still fail in practice for reasons that have nothing to do with the code itself:

- **Transition duration too slow.** Anything above roughly 300-400ms starts to feel sluggish rather than responsive, especially for something as frequently interacted with as a button. Fast, snappy transitions read as more polished than slow, deliberate ones for this specific use case.
- **Mismatched easing between hover-in and hover-out.** If hovering in feels smooth but the button snaps back abruptly when the cursor leaves, the whole effect feels unfinished. Use the same or a complementary easing curve for both directions.
- **Effects that fight the button's actual affordance.** A button that shrinks on hover reads as "pressed" or disabled to some users, working against the instinct that hovering should invite a click, not discourage one. Test any effect against how it actually feels to interact with, not just how it looks in isolation.
- **Applying a hero-worthy effect to every button on a dense page.** A magnetic pull or gradient sweep on twenty buttons in a pricing table or feature grid is exhausting rather than delightful. Match effect intensity to how prominent and infrequent the button actually is.
- **Forgetting to test with real button copy.** A hover effect designed and tested with a short placeholder label ("Click") can behave differently with your actual, longer CTA copy ("Start your free 14-day trial") — text wrapping or icon spacing issues often only show up with real content.

## Combining Effects Without Overdoing It

Several of the effects above pair well together rather than competing, if you're deliberate about it. Scale + shadow lift combined with a subtle icon slide reads as one cohesive effect rather than two competing ones, because they reinforce the same directional cue (something is lifting and moving toward the visitor). Fill sweep combined with a text color crossfade is a similarly natural pairing. The combinations to avoid: stacking two effects that both dramatically change the button's size or position (a magnetic pull plus a scale effect, for example) tends to feel jittery rather than intentional, since the two motions can visually fight each other rather than compound cleanly.

A simpler rule that holds up well in practice: pick one effect that changes the button's *shape or position* (scale, lift, magnetic pull) and, if you want a second layer, pair it with an effect that changes *color or fill* rather than another motion-based effect. That combination reads as considered; stacking multiple motion-heavy effects usually reads as trying too hard.

## Testing Your Hover Effects Properly

Before considering any of these effects production-ready:

- **Test at actual production speed**, not in a slow, unthrottled local preview — Framer's editor performance can differ from the published site's real-world load.
- **Test on the actual devices your audience uses**, particularly if a meaningful share of traffic is mobile, where hover doesn't apply the same way and your tap/active state is what actually matters.
- **Get a second opinion from someone who hasn't seen the effect yet.** Effects you've stared at for an hour while building them can feel more "finished" to you than they'll read to a first-time visitor encountering them cold.

If building and maintaining a full set of custom hover overrides isn't the best use of your time on a given project, [FramerHub's Components plugin](/plugins/framer-components) ships buttons with several of these patterns pre-built and configurable from the property panel, so you get the polish without maintaining the code override yourself.

## Accessibility: Don't Skip This

A few details that separate a genuinely polished hover system from one that quietly frustrates part of your audience:

- **Respect prefers-reduced-motion.** Wrap your animation values so users who've set this OS-level preference get an instant state change instead of full motion, rather than ignoring the setting entirely.
- **Always add a matching focus state**, not just hover. Keyboard users tabbing through your page need visible feedback that doesn't depend on a mouse cursor.
- **Add a tap/active state for touch devices.** Hover doesn't exist the same way on mobile, so a hover-only effect is invisible to a large share of visitors — make sure the button still gives feedback on tap.

## Choosing the Right Effect for the Right Button

Not every button needs the same treatment. A rough hierarchy that holds up in practice:

<table>
<thead>
  <tr>
    <th>
      Button role
    </th>
    
    <th>
      Recommended effect
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      Primary CTA (hero, pricing)
    </td>
    
    <td>
      Scale + shadow lift, or gradient border for high-brand moments
    </td>
  </tr>
  
  <tr>
    <td>
      Secondary button
    </td>
    
    <td>
      Simple color shift or subtle scale
    </td>
  </tr>
  
  <tr>
    <td>
      "Learn more" / navigational link
    </td>
    
    <td>
      Icon slide or underline draw
    </td>
  </tr>
  
  <tr>
    <td>
      Hero-section standout CTA
    </td>
    
    <td>
      Magnetic pull, used sparingly
    </td>
  </tr>
</tbody>
</table>

For a broader library of ready-to-use effects beyond buttons specifically — scroll reveals, card hovers, page transitions — our [Framer animations and hover effects guide](/blog/framer-animations-hover-effects) covers the fuller range. And if you'd rather not hand-code every override, our [component library](/components) ships buttons with several of these hover patterns already built in, configurable from the property panel.

## FAQ

**Can I build hover effects in Framer without code?**
Yes, for simple effects — Framer's native variants and interaction settings handle basic color, scale, and opacity changes on hover without any code. Code overrides open up more distinctive effects like magnetic pull or gradient border sweeps.

**Do hover effects work on mobile?**
Hover states don't exist the same way on touch devices, so a hover-only interaction is invisible to a large share of visitors. Add a matching tap/active state for mobile so the button still feels responsive without relying on hover.

**Will too many hover effects hurt performance?**
A handful of well-implemented hover effects won't measurably affect performance. Heavy effects (large blur filters, complex gradients recalculating on every frame) applied to many elements simultaneously can, so reserve the more elaborate effects for primary CTAs rather than every button on the page.

**Should every button on my site have the same hover effect?**
Primary and secondary buttons should feel visually related but not identical — a shared family of motion (e.g., all buttons scale slightly) with a distinct accent on your primary CTA communicates hierarchy better than one uniform effect everywhere.

**What's the most effective hover effect for conversion?**
Simple, immediate feedback (a slight scale or color shift) outperforms elaborate effects for most conversion-focused buttons — the goal is confirming the button is clickable, not entertaining the visitor. Save the more distinctive effects for hero CTAs or brand moments where personality matters more than raw conversion.
