User avatar

Jeroen Reumkens PRO

Button Hover Animation

Unlock Playground Access

Playgrounds let you build, test, and share frontend ideas instantly — right in your browser. Access is included in PRO. Just want Playgrounds? Pick a plan below.

Maker

€5,- / month

Unlimited Playgrounds access to build, experiment, and share without limits.

Join for €5 per month

Champion

€10,- / month

All the benefits of Maker, plus you help Frontend.fyi grow and get a Champion badge on your profile.

Join for €10 per month

Cancel anytime — no commitment.
Upgrade to PRO anytime and get a partial refund.We'll credit 100% of your first 3 months and 50% of the rest toward the PRO lifetime price.

Already a member? Login

Playground settings

Title

Description

Public

Editor settings


Packages

These packages can be imported in your JavaScript files.

Package name

Version

@

@

@

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
import { motion } from "motion/react";
import { spring } from "motion";

const variants = {
  resting: {
    y: "0%"
  },
  hover: {
    y: "-100%"
  }
};

const HoverButton = ({ text }) => {
  return (
    <motion.button 
      variants={{
        resting: {
          transition: {
            staggerChildren: 0.01,
            staggerDirection: -1
          },
          scale: 1
        },
        hover: {
          transition: {
            staggerChildren: 0.01,
            staggerDirection: 1
          },
          scale: 0.98
        }
      }}
      transition={{
        type: "spring",
        bounce: 0.25
      }}
      initial="resting"
      animate="resting"
      whileHover="hover">
      <span className="visually-hidden">{text}</span>
      <div className="letter-wrapper" aria-hidden>
        {text.split('').map((letter, index) => (
          <motion.span 
            transition={{
              type: "spring",
              bounce: 0.25
            }} 
            className="letter" variants={variants} key={index}>{letter}</motion.span>
        ))}
      </div>
    </motion.button>
  )
}

const HoverButtonCSS = ({ text, className }) => {
  return (
    <button 
      className={`stagger-button ${className}`}>
      <span className="visually-hidden">{text}</span>
      <div className="letter-wrapper" aria-hidden>
        {text.split('').map((letter, index) => (
          <motion.span style={{"--index": index}} className="letter" variants={variants} key={index}>{letter}</motion.span>
        ))}
      </div>
    </button>
  )
}

export const App = () => {
  return (
    <>
      <div 
        className="grid min-h-dvh place-items-center text-white">
        <div className="flex flex-col gap-3">
          <HoverButton text="Teaching you the" />
          <HoverButton text="craft of frontend" />
  
        </div>
      </div>
    </>
  );
}
One sec — editor's thinking…