Skip to content

Circle Timer

A copy-paste countdowns component in pure HTML, CSS & vanilla JS. Zero dependencies, framework-agnostic, MIT-licensed.

CountdownsHTMLCSSJavaScriptany framework
42

Copy into your project

HTML
<div class="nuda-circle-timer" role="timer" aria-label="Timer">
  <svg class="nuda-circle-timer__svg" viewBox="0 0 100 100" width="80" height="80">
    <circle class="nuda-circle-timer__track" cx="50" cy="50" r="44"
      fill="none" stroke="currentColor" stroke-width="4" />
    <circle class="nuda-circle-timer__progress" cx="50" cy="50" r="44"
      fill="none" stroke="currentColor" stroke-width="4"
      stroke-linecap="round" />
  </svg>
  <span class="nuda-circle-timer__value">60</span>
</div>
CSS
/* Circle Timer
   Circular countdown with animated SVG stroke.
   Customize: --timer-color, --timer-track, --timer-duration */

.nuda-circle-timer {
  --timer-color: #e4ff54;
  --timer-track: rgba(255, 255, 255, 0.08);
  --timer-duration: 60s;
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.nuda-circle-timer__svg {
  transform: rotate(-90deg);
}

.nuda-circle-timer__track {
  color: var(--timer-track);
}

.nuda-circle-timer__progress {
  color: var(--timer-color);
  /* circumference = 2 * PI * 44 = 276.46 */
  stroke-dasharray: 276.46;
  stroke-dashoffset: 0;
  animation: nuda-circle-countdown var(--timer-duration) linear forwards;
}

.nuda-circle-timer__value {
  position: absolute;
  color: #fff;
  font-size: 1.2rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

@keyframes nuda-circle-countdown {
  from { stroke-dashoffset: 0; }
  to   { stroke-dashoffset: 276.46; }
}

@media (prefers-reduced-motion: reduce) {
  .nuda-circle-timer__progress {
    animation: none;
  }
}
JavaScript
/* Circle Timer — Updates the number as the circle depletes. */

(function () {
  var timer = document.querySelector('.nuda-circle-timer');
  if (!timer) return;

  var valueEl = timer.querySelector('.nuda-circle-timer__value');
  if (!valueEl) return;

  var duration = 60; // seconds
  var remaining = duration;
  valueEl.textContent = remaining;

  var interval = setInterval(function () {
    remaining--;
    valueEl.textContent = Math.max(0, remaining);
    if (remaining <= 0) clearInterval(interval);
  }, 1000);
})();

How to use Circle Timer

Paste the HTML where you need it and the CSS into a global stylesheet (or a <style> tag). Every class is prefixed nuda- so it never collides with Tailwind or your own styles. Tweak the CSS custom properties to match your design system.

Works in React, Vue, Svelte, Astro, Next.js, Nuxt, Laravel Blade, Django, Rails — or a single .html file. No npm install, no build step.

More countdowns components

← Browse all NudaUI components