Creative Buttons
Animated, interactive and modern buttons for your interfaces.
Updated
How do you make a button animation that helps people click?
An animated button uses motion to show that it can be pressed and to confirm the click. The reliable techniques are CSS transitions on transform, box-shadow and background-position, pseudo-elements for shine and border effects, and a few lines of JavaScript for ripples or a magnetic pull toward the pointer.
How to choose, performance and accessibility
- For a main call to action, prefer one clear cue, such as Glow Pulse, Shine Sweep or Gradient Shift, over several at once; save Magnetic Button or Liquid Fill for creative sites.
- Keep the animation short (roughly 150 to 300 ms), give keyboard users the same feedback with
:focus-visible, and never convey a state by motion alone. - Gradient Shift and Ripple Effect are free with their full code; the other buttons on this page come with Premium.
View source code
<div class="demo-preview">
<button class="demo-btn btn-gradient-shift">Gradient Shift</button>
</div>.demo-preview,
.demo-preview *,
.demo-preview *::before,
.demo-preview *::after {
box-sizing: border-box
}
.demo-preview {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 250px;
overflow: hidden;
position: relative;
background: rgb(26, 26, 36);
color: rgb(255, 255, 255);
font-family: sans-serif;
}
.demo-btn {
padding: 16px 32px;
font-size: 1rem;
font-weight: 600;
border: none;
border-radius: 12px;
cursor: pointer;
font-family: inherit;
position: relative;
overflow: hidden;
}
.btn-gradient-shift {
background: linear-gradient(135deg, #6366f1, #8b5cf6, #d946ef);
background-size: 200% 200%;
color: white;
transition: all 0.5s ease;
}
.btn-gradient-shift:hover {
background-position: 100% 100%;
transform: translateY(-3px);
box-shadow: 0 15px 35px rgba(99, 102, 241, 0.4);
}/* Pure CSS — no JavaScript required */View source code
<div class="demo-preview">
<button class="demo-btn btn-ripple" onclick="createRipple(event)">Ripple Effect</button>
</div>.demo-preview,
.demo-preview *,
.demo-preview *::before,
.demo-preview *::after {
box-sizing: border-box
}
.demo-preview {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 250px;
overflow: hidden;
position: relative;
background: rgb(26, 26, 36);
color: rgb(255, 255, 255);
font-family: sans-serif;
}
.demo-btn {
padding: 16px 32px;
font-size: 1rem;
font-weight: 600;
border: none;
border-radius: 12px;
cursor: pointer;
font-family: inherit;
position: relative;
overflow: hidden;
}
.btn-ripple {
background: #6366f1;
color: white;
transition: all 0.3s ease;
}
.btn-ripple .ripple-circle {
position: absolute;
border-radius: 50%;
background: rgba(255, 255, 255, 0.4);
transform: scale(0);
animation: ripple 0.6s linear;
pointer-events: none;
}
@keyframes ripple {
to {
transform: scale(4);
opacity: 0;
}
}(function() {
// Ripple Effect
function createRipple(e) {
const btn = e.currentTarget;
const rect = btn.getBoundingClientRect();
const circle = document.createElement('span');
const diameter = Math.max(btn.clientWidth, btn.clientHeight);
const radius = diameter / 2;
circle.style.width = circle.style.height = `${diameter}px`;
circle.style.left = `${e.clientX - rect.left - radius}px`;
circle.style.top = `${e.clientY - rect.top - radius}px`;
circle.classList.add('ripple-circle');
const ripple = btn.querySelector('.ripple-circle');
if (ripple) ripple.remove();
circle.addEventListener('animationend', () => circle.remove());
btn.appendChild(circle);
}
window.createRipple = createRipple;
})();Press Feedback
Tactile micro-interaction with click compression for optimal user feedback.
Effect page →CTA Gradient Border
Animated gradient border perfect for premium call-to-action. Inspired by CTA Gallery.
Effect page →Neon Pulse
Pulsing neon box-shadow with continuous animation for an intense cyberpunk effect.
Effect page →Gummy Elastic
Elastic click effect with cubic-bezier curve for a natural and fun bounce.
Effect page →Glitch Effect
Glitch effect with pseudo-elements and chromatic shift in retro gaming style.
Effect page →Gradient Border Animated
Rotating gradient border with continuous animation using CSS @property.
Effect page →Studio Pro Headphones
149 €Magnetic Add to Cart
Add-to-cart micro-interaction: magnetic button, particle burst, item flies in a curve to the cart with an animated counter. The satisfying click that drives purchases.
💡 Perfect for: e-commerce, product page, Black Friday, cart, any "add / save / like" CTA.
View source code
<div class="demo-preview">
<div class="atc-scene" data-atc data-icon="🎧">
<div class="atc-cart-wrap">
<span class="atc-cart" aria-hidden="true">🛒</span>
<span class="atc-count" data-atc-count aria-label="Items in cart">0</span>
</div>
<div class="atc-product">
<div class="atc-thumb" aria-hidden="true">🎧</div>
<div class="atc-info">
<h3>Studio Pro Headphones</h3>
<span class="atc-price">149 €</span>
<div><button type="button" class="atc-btn" data-atc-btn>Add to cart</button></div>
</div>
</div>
</div>
</div>.demo-preview,
.demo-preview *,
.demo-preview *::before,
.demo-preview *::after {
box-sizing: border-box
}
.demo-preview {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
min-height: 200px;
position: relative;
background: rgb(26, 26, 36);
color: rgb(255, 255, 255);
font-family: sans-serif;
}
.atc-scene {
position: relative;
width: 100%;
min-height: 240px;
border-radius: 14px;
overflow: hidden;
isolation: isolate;
background: radial-gradient(circle at 70% 20%, #1c1330, #0b0a14 75%);
padding: 22px;
box-sizing: border-box;
}
.atc-cart {
position: absolute;
top: 16px;
right: 18px;
font-size: 26px;
line-height: 1;
}
.atc-count {
position: absolute;
top: -8px;
right: -10px;
min-width: 18px;
height: 18px;
padding: 0 4px;
box-sizing: border-box;
background: #ef4444;
color: #fff;
font-size: 11px;
font-weight: 700;
border-radius: 999px;
display: grid;
place-items: center;
}
.atc-cart-wrap {
position: absolute;
top: 16px;
right: 18px;
}
.atc-product {
display: flex;
align-items: center;
gap: 16px;
max-width: 360px;
margin-top: 34px;
}
.atc-thumb {
width: 78px;
height: 78px;
border-radius: 14px;
background: linear-gradient(135deg, #6366f1, #d946ef);
display: grid;
place-items: center;
font-size: 38px;
flex: none;
}
.atc-info h3 {
margin: 0 0 2px;
font-size: 16px;
color: #fff;
}
.atc-info .atc-price {
color: #a78bfa;
font-weight: 700;
}
.atc-btn {
margin-top: 14px;
border: 0;
cursor: pointer;
background: linear-gradient(135deg, #f59e0b, #ef4444);
color: #fff;
font-weight: 700;
font-size: 14px;
padding: 11px 20px;
border-radius: 10px;
transition: transform .12s, box-shadow .2s;
will-change: transform;
}
.atc-btn:hover {
box-shadow: 0 8px 24px rgba(245, 158, 11, .35);
}
.atc-btn:active {
transform: scale(.96);
}
.atc-particle {
position: absolute;
width: 7px;
height: 7px;
border-radius: 50%;
background: #fbbf24;
pointer-events: none;
transform: translate(-50%, -50%);
animation: atc-burst .6s ease-out forwards;
z-index: 4;
}
.atc-fly {
position: absolute;
font-size: 30px;
pointer-events: none;
z-index: 5;
transform: translate(-50%, -50%);
}
.atc-pop {
animation: atc-pop .32s ease;
}
.atc-bump {
animation: atc-bump .4s ease;
}
@media (prefers-reduced-motion: reduce) {
.atc-btn {
transition: none;
}
}
@keyframes atc-burst {
to {
transform: translate(-50%, -50%) translate(var(--dx), var(--dy)) scale(.2);
opacity: 0;
}
}
@keyframes atc-pop {
0% {
transform: scale(1);
}
40% {
transform: scale(1.6);
}
100% {
transform: scale(1);
}
}
@keyframes atc-bump {
0%,
100% {
transform: translateY(0);
}
30% {
transform: translateY(-7px) rotate(-8deg);
}
}(function() {
(function() {
var reduceMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
document.querySelectorAll('[data-atc]').forEach(function(scene) {
var btn = scene.querySelector('[data-atc-btn]');
var cart = scene.querySelector('.atc-cart');
var countEl = scene.querySelector('[data-atc-count]');
var icon = scene.dataset.icon || '🛍️';
var n = 0;
if (!reduceMotion) {
btn.addEventListener('pointermove', function(e) {
var r = btn.getBoundingClientRect();
var mx = e.clientX - (r.left + r.width / 2),
my = e.clientY - (r.top + r.height / 2);
btn.style.transform = 'translate(' + (mx * 0.22) + 'px,' + (my * 0.35) + 'px)';
});
btn.addEventListener('pointerleave', function() {
btn.style.transform = '';
});
}
function bump() {
n++;
countEl.textContent = n;
countEl.classList.remove('atc-pop');
void countEl.offsetWidth;
countEl.classList.add('atc-pop');
cart.classList.remove('atc-bump');
void cart.offsetWidth;
cart.classList.add('atc-bump');
}
btn.addEventListener('click', function() {
if (reduceMotion) {
bump();
return;
}
var br = btn.getBoundingClientRect(),
cr = cart.getBoundingClientRect(),
sr = scene.getBoundingClientRect();
var x0 = br.left + br.width / 2 - sr.left,
y0 = br.top + br.height / 2 - sr.top;
var x1 = cr.left + cr.width / 2 - sr.left,
y1 = cr.top + cr.height / 2 - sr.top;
for (var i = 0; i < 14; i++) {
var p = document.createElement('span');
p.className = 'atc-particle';
p.style.left = x0 + 'px';
p.style.top = y0 + 'px';
var a = Math.random() * 6.2832,
d = 24 + Math.random() * 46;
p.style.setProperty('--dx', Math.cos(a) * d + 'px');
p.style.setProperty('--dy', Math.sin(a) * d + 'px');
scene.appendChild(p);
(function(el) {
setTimeout(function() {
el.remove();
}, 650);
})(p);
}
var chip = document.createElement('span');
chip.className = 'atc-fly';
chip.textContent = icon;
chip.style.left = x0 + 'px';
chip.style.top = y0 + 'px';
scene.appendChild(chip);
var t0 = performance.now(),
dur = 620,
cx = (x0 + x1) / 2,
cy = Math.min(y0, y1) - 70;
(function anim(t) {
var k = Math.min((t - t0) / dur, 1);
var e = k < .5 ? 2 * k * k : 1 - Math.pow(-2 * k + 2, 2) / 2,
m = 1 - e;
var x = m * m * x0 + 2 * m * e * cx + e * e * x1;
var y = m * m * y0 + 2 * m * e * cy + e * e * y1;
chip.style.transform = 'translate(-50%,-50%) translate(' + (x - x0) + 'px,' + (y - y0) + 'px) scale(' + (1 - 0.55 * e) + ')';
chip.style.opacity = String(1 - 0.25 * e);
if (k < 1) requestAnimationFrame(anim);
else {
chip.remove();
bump();
}
})(t0);
});
});
})();
})();