<button class="cart-btn">
<span class="btn-content">
<span class="btn-text">Add to Cart</span>
<svg class="icon-cart" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<circle cx="9" cy="21" r="1"></circle>
<circle cx="20" cy="21" r="1"></circle>
<path d="M1 1h4l2.68 13.39a2 2 0 0 0 2 1.61h9.72a2 2 0 0 0 2-1.61L23 6H6"></path>
</svg>
</span>
<div class="loader"></div>
<svg class="icon-check" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3">
<polyline points="20 6 9 17 4 12"></polyline>
</svg>
</button>* { box-sizing: border-box; }
body {
font-family: system-ui, "Segoe UI", sans-serif;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
background: #f1f5f9;
}
.cart-btn {
position: relative;
background: #1e293b;
color: white;
border: none;
border-radius: 12px;
padding: 14px 28px;
font-size: 16px;
font-weight: 600;
cursor: pointer;
overflow: hidden;
transition: all 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275);
display: flex;
align-items: center;
justify-content: center;
min-width: 160px;
height: 54px;
box-shadow: 0 4px 6px -1px rgba(0,0,0,0.1);
}
.cart-btn:hover {
background: #334155;
transform: translateY(-2px);
box-shadow: 0 10px 15px -3px rgba(0,0,0,0.15);
}
.btn-content {
display: flex;
align-items: center;
gap: 10px;
transition: opacity 0.3s, transform 0.3s;
}
.icon-cart {
width: 20px;
height: 20px;
}
.loader {
display: none;
width: 24px;
height: 24px;
border: 3px solid rgba(255,255,255,0.3);
border-top-color: white;
border-radius: 50%;
animation: spin 0.8s linear infinite;
position: absolute;
}
.icon-check {
display: none;
width: 28px;
height: 28px;
color: white;
position: absolute;
stroke-dasharray: 24;
stroke-dashoffset: 24;
animation: drawCheck 0.4s forwards 0.1s;
}
/* STATE: Loading */
.cart-btn.is-loading {
width: 54px; /* Collapse to circle */
min-width: 54px;
border-radius: 50%;
background: #334155;
cursor: default;
transform: none;
padding: 0;
}
.cart-btn.is-loading .btn-content {
opacity: 0;
transform: scale(0.5);
}
.cart-btn.is-loading .loader {
display: block;
}
/* STATE: Added */
.cart-btn.is-added {
width: 54px;
min-width: 54px;
border-radius: 50%;
background: #22c55e; /* Green */
cursor: default;
padding: 0;
}
.cart-btn.is-added .btn-content,
.cart-btn.is-added .loader {
display: none;
}
.cart-btn.is-added .icon-check {
display: block;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
@keyframes drawCheck {
to { stroke-dashoffset: 0; }
}const btn = document.querySelector(".cart-btn");
btn.addEventListener("click", () => {
// Prevent multiple clicks
if (btn.classList.contains("is-loading") || btn.classList.contains("is-added")) return;
// 1. Start Loading
btn.classList.add("is-loading");
// Simulate API request (1.5s)
setTimeout(() => {
// 2. Success State
btn.classList.remove("is-loading");
btn.classList.add("is-added");
// 3. Reset after 2.5s so user can add again
setTimeout(() => {
btn.classList.remove("is-added");
}, 2500);
}, 1500);
});Nothing to show yetType HTML, CSS or JavaScript and your page appears here.
Click any element to find its code Esc
Check this code before you run it
It came from a shared link. It runs with fewer permissions, so it cannot open pop-ups, submit forms or start downloads.
0.00s / 0.00s
Nothing has animated yet. Hover, click or type in the preview and each CSS animation, transition or
element.animate() call shows up here as it plays.