About this snippet

Transform a static download link into an engaging micro-interaction. This button seamlessly transitions from a download icon to a loading spinner, and finally to a success checkmark, providing clear and satisfying feedback to the user.

Size
2.8 KB
Uses
HTML, CSS, JavaScript
Loads
Nothing external
Views
527
<button class="dl-button" id="dlBtn" onclick="startDownload()">
  <span class="label">Download</span>
  <div class="icon-container">
    <svg class="dl-icon" viewBox="0 0 24 24" width="24" height="24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path><polyline points="7 10 12 15 17 10"></polyline><line x1="12" y1="15" x2="12" y2="3"></line></svg>
  </div>
</button>
.dl-button {
  font-family: system-ui, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  background-color: #2563eb;
  color: #fff;
  border: none;
  padding: 14px 28px;
  border-radius: 50px;
  font-size: 1rem;
  font-weight: 600;
  cursor: pointer;
  overflow: hidden;
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  box-shadow: 0 4px 6px -1px rgba(37, 99, 235, 0.3);
  min-width: 160px;
}
.dl-button:hover {
  background-color: #1d4ed8;
  transform: translateY(-2px);
  box-shadow: 0 10px 15px -3px rgba(37, 99, 235, 0.4);
}
.dl-button.loading {
  background-color: #1f2937;
  cursor: wait;
  pointer-events: none;
}
.dl-button.success {
  background-color: #10b981;
  cursor: default;
  pointer-events: none;
}
.icon-container {
  display: flex;
  align-items: center;
  justify-content: center;
}
/* Spinner Animation */
.spinner {
  animation: spin 1s linear infinite;
}
@keyframes spin {
  from { transform: rotate(0deg); }
  to { transform: rotate(360deg); }
}
function startDownload() {
  const btn = document.getElementById("dlBtn");
  const iconContainer = btn.querySelector(".icon-container");
  const label = btn.querySelector(".label");
  
  // Icons
  const loadingIcon = '<svg class="spinner" viewBox="0 0 24 24" width="24" height="24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12a9 9 0 1 1-6.219-8.56"></path></svg>';
  const checkIcon = '<svg viewBox="0 0 24 24" width="24" height="24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"></polyline></svg>';
  const originalIcon = iconContainer.innerHTML;
  const originalText = label.innerText;

  // Start Loading
  btn.classList.add("loading");
  label.innerText = "Downloading...";
  iconContainer.innerHTML = loadingIcon;

  // Simulate Download Finish
  setTimeout(() => {
    btn.classList.remove("loading");
    btn.classList.add("success");
    label.innerText = "Saved!";
    iconContainer.innerHTML = checkIcon;

    // Reset Button
    setTimeout(() => {
      btn.classList.remove("success");
      label.innerText = originalText;
      iconContainer.innerHTML = originalIcon;
    }, 2500);
  }, 2000);
}
Esc
↑↓ moveEnter select

Start from a template

Open an .html file, or HTML, CSS, JS, Markdown, Less or TypeScript files. You can also drop them here. Styles and scripts go into their panes.

Share

Source

Keyboard shortcuts

Save