Back to CSS Floating Buttons Loading Spinner CSS + JS
Share
.cfb-load {
  position: relative;
  width: 52px; height: 52px;
  border: 0; border-radius: 50%;
  background: linear-gradient(135deg, #2eb88a, #06b6d4);
  color: #fff;
  cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  box-shadow: 0 6px 16px rgba(46,184,138,0.35);
  transition: transform 0.2s, opacity 0.2s;
}
.cfb-load:hover { transform: translateY(-2px); }
.cfb-load:focus-visible { outline: 2px solid #fff; outline-offset: 3px; }
.cfb-load:disabled { cursor: wait; opacity: 0.85; }
.cfb-load svg { width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; transition: opacity 0.2s; }
.cfb-load-spin {
  position: absolute; inset: 14px;
  border: 2px solid rgba(255,255,255,0.3);
  border-top-color: #fff;
  border-radius: 50%;
  opacity: 0;
  animation: cfb-load-rot 0.7s linear infinite;
}
.cfb-load.is-loading .cfb-load-icon { opacity: 0; }
.cfb-load.is-loading .cfb-load-spin { opacity: 1; }
@keyframes cfb-load-rot { to { transform: rotate(360deg); } }
<button type="button" class="cfb-load" aria-label="Save changes" data-cfb-load>
  <svg class="cfb-load-icon" viewBox="0 0 24 24" aria-hidden="true">
    <path d="M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z" />
    <polyline points="17 21 17 13 7 13 7 21" />
    <polyline points="7 3 7 8 15 8" />
  </svg>
  <span class="cfb-load-spin" aria-hidden="true"></span>
</button>
// Loading FAB — click triggers spinner state, returns to ready after 1.5s
document.querySelectorAll('[data-cfb-load]').forEach(function (btn) {
  btn.addEventListener('click', function () {
    if (btn.classList.contains('is-loading')) return;
    btn.classList.add('is-loading');
    btn.disabled = true;
    setTimeout(function () {
      btn.classList.remove('is-loading');
      btn.disabled = false;
    }, 1500);
  });
});
Live preview Edit any tab — preview updates live Ready