{ CF }

30 CSS Badges

Countdown Ring

Ring depletes continuously in real time. Color shifts green → amber → red as the deadline approaches. The depletion rate is the data. A static badge cannot know what time it is.

CSS + JS MIT licensed

Countdown Ring the 15th of 30 designs in the 30 CSS Badges collection. The design pairs CSS styling with a small amount of JavaScript for interactivity. Copy the HTML, CSS and JavaScript panels below into your project — the JS is self-contained, has zero dependencies, and is safe to drop into any framework (React, Vue, Svelte, plain HTML). The design honours prefers-reduced-motion and uses real semantic markup, so it ships accessibility-ready out of the box.

Live preview

Open in playground

The code

<div class="cd-stage">
  <div class="cd-wrap">
    <div class="cd-event">Sprint Review</div>
    <div class="cd-ring-wrap">
      <svg viewBox="0 0 180 180" aria-hidden="true">
        <circle class="cd-ring-track" cx="90" cy="90" r="81"/>
        <circle class="cd-ring-fill" id="cd-ring" cx="90" cy="90" r="81" stroke="#0cce6b"/>
      </svg>
      <div class="cd-inner">
        <div class="cd-time" id="cd-time">02:34:00</div>
        <div class="cd-label">remaining</div>
      </div>
    </div>
    <div class="cd-deadline" id="cd-deadline">Deadline · Today, 17:00</div>
  </div>
</div>
.cd-stage {
  background: #fafaf7;
  padding: 60px 48px;
  display: flex;
  flex-direction: column;
  gap: 20px;
  align-items: center;
  justify-content: center;
  min-height: 400px;
}
.cd-wrap {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
}
.cd-ring-wrap {
  position: relative;
  width: 180px;
  height: 180px;
}
.cd-ring-wrap svg {
  width: 100%;
  height: 100%;
  transform: rotate(-90deg);
}
.cd-ring-track {
  fill: none;
  stroke: #e8e4da;
  stroke-width: 9;
}
.cd-ring-fill {
  fill: none;
  stroke-width: 9;
  stroke-linecap: round;
  stroke-dasharray: 508;
  stroke-dashoffset: 0;
  transition: stroke-dashoffset 1s linear, stroke 0.8s ease;
}
.cd-inner {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
}
.cd-time {
  font-family: ui-monospace, "JetBrains Mono", monospace;
  font-size: 26px;
  font-weight: 700;
  color: #1a1612;
  letter-spacing: -0.02em;
  line-height: 1;
}
.cd-label {
  font-family: system-ui, "Bricolage Grotesque", sans-serif;
  font-size: 9px;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: #4a4239;
}
.cd-deadline {
  font-family: system-ui, "Bricolage Grotesque", sans-serif;
  font-size: 11px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: #aaa;
  text-align: center;
}
.cd-event {
  font-family: Georgia, "Fraunces", serif;
  font-size: 20px;
  font-style: italic;
  color: #1a1612;
  text-align: center;
}
// Countdown ring — 4h total sprint, ~2h34m initially remaining.
// Ring depletes continuously, color shifts at 50% and 20% thresholds.
(function () {
  var TOTAL_MS = 4 * 3600 * 1000;
  var deadline = new Date(Date.now() + 2 * 3600 * 1000 + 34 * 60 * 1000);
  var ring   = document.getElementById('cd-ring');
  var timeEl = document.getElementById('cd-time');
  var deadEl = document.getElementById('cd-deadline');
  var CIRCUM = 2 * Math.PI * 81;

  function pad2(n) { return String(n).padStart(2, '0'); }
  function tick() {
    var remaining = Math.max(0, deadline - Date.now());
    var frac = remaining / TOTAL_MS;
    ring.style.strokeDashoffset = CIRCUM * (1 - frac);
    ring.style.stroke = frac > 0.5 ? '#0cce6b' : frac > 0.2 ? '#ffa400' : '#ff4e42';
    var h = Math.floor(remaining / 3600000);
    var m = Math.floor((remaining % 3600000) / 60000);
    var s = Math.floor((remaining % 60000) / 1000);
    timeEl.textContent = pad2(h) + ':' + pad2(m) + ':' + pad2(s);
    deadEl.textContent = 'Deadline · Today, ' + deadline.getHours() + ':' + pad2(deadline.getMinutes());
  }
  tick();
  setInterval(tick, 1000);
})();

Search CodeFronts

Loading…