UI Snippet
⬇️ Animated Download Button
A modern download button with progress bar, idle shimmer, and success state. Pure HTML, CSS, and JavaScript — no libraries.
🔍 Live Demo
Click any button below to see the animation. Each has a different style.
Gradient Button
Outline Style
Terminal Style
📘 What happens when you click
1. Button enters downloading state
2. Progress bar fills from 0% → 100%
3. Label updates to "Downloading… 45%"
4. On completion, button flips to a green done state
5. After 2 seconds, resets back to idle
2. Progress bar fills from 0% → 100%
3. Label updates to "Downloading… 45%"
4. On completion, button flips to a green done state
5. After 2 seconds, resets back to idle
💻 Complete Code
<!-- HTML -->
<button class="dl-btn" onclick="runDownload(this)">
<span class="progress"></span>
<span class="icon"><i class="fas fa-download"></i></span>
<span class="label">Download File</span>
</button>
<!-- CSS -->
.dl-btn {
position: relative;
display: inline-flex;
align-items: center;
justify-content: center;
gap: 0.6rem;
min-width: 220px;
height: 56px;
padding: 0 2rem;
background: linear-gradient(135deg, #3b82f6, #8b5cf6);
color: #fff;
font-weight: 600;
border: none;
border-radius: 999px;
cursor: pointer;
overflow: hidden;
transition: transform 0.2s ease, box-shadow 0.3s ease;
box-shadow: 0 8px 20px -8px rgba(59,130,246,0.6);
}
.dl-btn:hover:not(:disabled) {
transform: translateY(-2px);
box-shadow: 0 14px 28px -10px rgba(139,92,246,0.7);
}
/* Shimmer sweep on hover */
.dl-btn::before {
content: "";
position: absolute;
top: 0; left: -100%;
width: 60%; height: 100%;
background: linear-gradient(90deg, transparent, rgba(255,255,255,0.35), transparent);
transition: left 0.6s ease;
}
.dl-btn:hover:not(:disabled)::before { left: 130%; }
/* Progress fill */
.dl-btn .progress {
position: absolute;
left: 0; top: 0; bottom: 0;
width: 0%;
background: rgba(255,255,255,0.25);
transition: width 0.15s linear;
}
/* Content above progress */
.dl-btn .label,
.dl-btn .icon { position: relative; z-index: 1; }
/* Downloading state */
.dl-btn.downloading .icon { animation: bounce-arrow 1s infinite; }
@keyframes bounce-arrow {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(4px); }
}
/* Done state */
.dl-btn.done {
background: linear-gradient(135deg, #22c55e, #16a34a);
box-shadow: 0 8px 20px -8px rgba(34,197,94,0.6);
}
.dl-btn.done .icon { animation: pop 0.4s ease; }
@keyframes pop {
0% { transform: scale(0.6); }
60% { transform: scale(1.25); }
100% { transform: scale(1); }
}
<!-- JavaScript -->
function runDownload(btn) {
if (btn.classList.contains('downloading') || btn.classList.contains('done')) return;
const progress = btn.querySelector('.progress');
const label = btn.querySelector('.label');
const icon = btn.querySelector('.icon');
const originalLabel = label.textContent;
const originalIcon = icon.innerHTML;
btn.classList.add('downloading');
icon.innerHTML = '<i class="fas fa-download"></i>';
let pct = 0;
const tick = setInterval(() => {
pct += Math.random() * 12 + 4; // 4–16% per tick
if (pct >= 100) {
pct = 100;
progress.style.width = '100%';
label.textContent = 'Completed!';
icon.innerHTML = '<i class="fas fa-check"></i>';
btn.classList.remove('downloading');
btn.classList.add('done');
clearInterval(tick);
setTimeout(() => {
progress.style.width = '0%';
label.textContent = originalLabel;
icon.innerHTML = originalIcon;
btn.classList.remove('done');
}, 2000);
} else {
progress.style.width = pct + '%';
label.textContent = `Downloading… ${Math.floor(pct)}%`;
}
}, 200);
}
🧠 How It Works
- Three states: idle → downloading → done, controlled by CSS classes.
- Progress bar: a .progress span whose width is animated in JS.
- Shimmer effect: a pseudo-element sweeping across the button on hover.
- Icon change: download icon → check icon on completion.
- Auto reset: after 2 seconds, the button returns to idle so it can be reused.
- No libraries: pure HTML, CSS keyframes, and vanilla JS.
- Accessible: real <button> element, keyboard-friendly, disabled during progress.
💡 Why This Snippet?
- Real UX pattern — used by file hosts, SaaS apps, and download portals.
- Three style variants — gradient, outline, and terminal.
- Copy-paste ready — works in any project, no build step.
- Customizable — change colors, duration, or add a real download via fetch().
- Lightweight — under 60 lines of JS.