AnimationsSimpleApril 8, 2026
Emoji Pill Spring Reveal
A hidden pill element sits behind a button rotated 180deg and scaled to zero. On hover it spins to 0deg, scales to full size, and springs into view using a Framer Motion spring transition.
View Full Demo →Preview
Source
demo.jsx
import EmojiPillSpringReveal from "./index.jsx";
import { emojiPillSpringReveal } from "@/content/animations/demo-data.js";
import styles from "./demo.module.css";
export default function EmojiPillSpringRevealDemo() {
return (
<div className={styles.demo}>
<div className={styles.hero}>
<p className={styles.label}>Available for work</p>
<h1 className={styles.heading}>Let's build<br />something great</h1>
<EmojiPillSpringReveal {...emojiPillSpringReveal} />
</div>
</div>
);
}
index.jsx
"use client";
import { motion } from "framer-motion";
import styles from "./styles.module.css";
export default function EmojiPillSpringReveal({ buttons = [] }) {
return (
<div className={styles.row}>
{buttons.map((btn) => (
<motion.a
key={btn.label}
href={btn.href}
className={styles.button}
whileHover="hover"
initial="rest"
>
<span className={styles.label}>{btn.label}</span>
<motion.span
className={styles.pill}
variants={{
rest: { rotate: 180, scale: 0, opacity: 0 },
hover: {
rotate: 0,
scale: 1,
opacity: 1,
transition: { type: "spring", stiffness: 400, damping: 20 },
},
}}
>
{btn.emoji}
</motion.span>
</motion.a>
))}
</div>
);
}
demo.module.css
.demo {
min-height: 100vh;
background: #0a0a0a;
display: flex;
align-items: center;
justify-content: center;
}
.hero {
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
gap: 2.5rem;
padding: 4rem 2rem;
}
.label {
font-size: 0.75rem;
font-weight: 500;
letter-spacing: 0.14em;
text-transform: uppercase;
color: rgba(255, 255, 255, 0.35);
}
.heading {
font-size: clamp(3rem, 8vw, 7rem);
font-weight: 500;
letter-spacing: -0.03em;
line-height: 0.95;
color: #ffffff;
}
styles.module.css
.row {
display: flex;
gap: 1rem;
padding: 3rem;
justify-content: center;
flex-wrap: wrap;
}
.button {
position: relative;
display: inline-flex;
align-items: center;
gap: 0.5rem;
padding: 0.75rem 1.5rem;
font-size: 0.9375rem;
font-weight: 500;
font-family: inherit;
color: #1a1a1a;
background: #f5f5f5;
border: 1px solid #e5e5e5;
border-radius: 9999px;
text-decoration: none;
cursor: pointer;
letter-spacing: -0.01em;
overflow: hidden;
}
.label {
position: relative;
z-index: 1;
}
.pill {
display: inline-flex;
align-items: center;
justify-content: center;
font-size: 1rem;
transform-origin: center;
}
Dependencies
framer-motion