SolutionsCase StudiesAI ToolsResourcesAboutContact
Get Your Free AI Automation Audit Book a Free 30-Minute Strategy Call
Playground~/frontend Open editor

~/css/tailwind-countdown-timers

6 Tailwind Countdown Timers

0 Tailwind6 with JSPublished 2026-10-05Free · no sign-up

Six countdowns styled with Tailwind and a few lines of JavaScript: four time boxes, a sale banner with an inline timer, a one-minute ring timer with controls, flip-style cards counting to midnight, a launch countdown with progress and a resend code button.

01. Tailwind Countdown Boxes

TailwindCountdownTimer

Days, hours, minutes and seconds in four dark tiles, with tabular-nums so the digits never shift as they change. The group has role="timer", which screen readers treat as a live region that stays quiet unless asked.

View code
<div role="timer" aria-label="Time left in the sale" class="flex gap-2">
  <div class="grid w-16 justify-items-center rounded-xl bg-slate-900 py-3 text-white"><span data-u="d" class="text-2xl font-black tabular-nums">00</span><span class="text-xs text-slate-300">days</span></div>
  <div class="grid w-16 justify-items-center rounded-xl bg-slate-900 py-3 text-white"><span data-u="h" class="text-2xl font-black tabular-nums">00</span><span class="text-xs text-slate-300">hours</span></div>
  <div class="grid w-16 justify-items-center rounded-xl bg-slate-900 py-3 text-white"><span data-u="m" class="text-2xl font-black tabular-nums">00</span><span class="text-xs text-slate-300">min</span></div>
  <div class="grid w-16 justify-items-center rounded-xl bg-slate-900 py-3 text-white"><span data-u="s" class="text-2xl font-black tabular-nums">00</span><span class="text-xs text-slate-300">sec</span></div>
</div>
var end = Date.now() + ((2 * 24 + 5) * 3600 + 42 * 60) * 1000, box = document.querySelector('[role=timer]');
function pad(n) { return String(n).padStart(2, '0'); }
function tick() { var s = Math.max(0, Math.floor((end - Date.now()) / 1000)), v = { d: Math.floor(s / 86400), h: Math.floor(s % 86400 / 3600), m: Math.floor(s % 3600 / 60), s: s % 60 }; box.querySelectorAll('[data-u]').forEach(function (el) { el.textContent = pad(v[el.dataset.u]); }); }
tick(); setInterval(tick, 1000);

02. Tailwind Sale Banner with Inline Countdown

TailwindCountdownBanner

A slim promotional banner with the remaining time inline in a monospace pill and a link to the sale. It wraps cleanly on small screens with flex-wrap and keeps the timer's width steady with tabular figures.

View code
<div class="flex w-full max-w-sm flex-wrap items-center justify-center gap-x-3 gap-y-2 rounded-xl bg-rose-700 px-4 py-3 text-sm text-white">
  <p>Autumn sale ends in <span id="twct2" role="timer" class="rounded bg-black/25 px-1.5 py-0.5 font-mono font-bold tabular-nums">00:00:00</span></p>
  <a href="#sale" class="font-semibold underline underline-offset-2 hover:no-underline">Shop now →</a>
</div>
var end = Date.now() + (2 * 3600 + 14 * 60 + 9) * 1000, el = document.getElementById('twct2');
function pad(n) { return String(n).padStart(2, '0'); }
function tick() { var s = Math.max(0, Math.floor((end - Date.now()) / 1000)); el.textContent = pad(Math.floor(s / 3600)) + ':' + pad(Math.floor(s % 3600 / 60)) + ':' + pad(s % 60); }
tick(); setInterval(tick, 1000);

03. Tailwind Circular Countdown with Controls

TailwindCountdownSVG

A one-minute timer whose ring empties as the seconds pass, with Start, Pause and Reset. The ring is an SVG circle with pathLength="100", so the dash offset is simply the percentage of time used.

View code
<div class="grid justify-items-center gap-3">
  <div class="relative size-32">
    <svg aria-hidden="true" viewBox="0 0 120 120" class="size-32 -rotate-90"><circle cx="60" cy="60" r="52" fill="none" stroke-width="10" class="stroke-slate-700"/><circle id="twct3c" cx="60" cy="60" r="52" fill="none" stroke-width="10" stroke-linecap="round" pathLength="100" class="stroke-emerald-400 transition-[stroke-dashoffset] duration-1000 ease-linear [stroke-dasharray:100] motion-reduce:transition-none"/></svg>
    <p id="twct3t" role="timer" class="absolute inset-0 grid place-items-center text-2xl font-black tabular-nums text-white">1:00</p>
  </div>
  <div class="flex gap-2"><button id="twct3s" type="button" class="rounded-lg bg-emerald-400 px-4 py-2 text-sm font-bold text-slate-900 hover:bg-emerald-300 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-emerald-300">Start</button><button id="twct3r" type="button" class="rounded-lg px-4 py-2 text-sm font-semibold text-slate-200 ring-1 ring-slate-600 hover:bg-white/10 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-slate-300">Reset</button></div>
</div>
var left = 60, t = null, c = document.getElementById('twct3c'), tx = document.getElementById('twct3t'), s = document.getElementById('twct3s');
function draw() { tx.textContent = Math.floor(left / 60) + ':' + String(left % 60).padStart(2, '0'); c.style.strokeDashoffset = 100 - left / 60 * 100; }
function stop() { clearInterval(t); t = null; s.textContent = 'Start'; }
s.onclick = function () { if (t) { stop(); return; } if (!left) left = 60; s.textContent = 'Pause'; t = setInterval(function () { left--; draw(); if (!left) { stop(); tx.textContent = 'Done'; } }, 1000); };
document.getElementById('twct3r').onclick = function () { stop(); left = 60; draw(); };
draw();

04. Tailwind Split-Card Countdown to Midnight

TailwindCountdownCards

Hours, minutes and seconds on dark cards with a thin line across the middle, the look of a flip clock without the flipping. The line is an after: pseudo-element, and the timer counts down to the visitor's local midnight.

View code
<div class="grid justify-items-center gap-2">
  <p class="text-sm font-semibold text-slate-300">Today’s deal resets in</p>
  <div id="twct4" role="timer" class="flex items-center gap-1.5 text-3xl font-black tabular-nums text-white">
    <span data-u="h" class="relative rounded-lg bg-slate-800 px-3 py-2 after:absolute after:inset-x-0 after:top-1/2 after:h-px after:bg-black/60">00</span><span aria-hidden="true" class="text-slate-500">:</span>
    <span data-u="m" class="relative rounded-lg bg-slate-800 px-3 py-2 after:absolute after:inset-x-0 after:top-1/2 after:h-px after:bg-black/60">00</span><span aria-hidden="true" class="text-slate-500">:</span>
    <span data-u="s" class="relative rounded-lg bg-slate-800 px-3 py-2 after:absolute after:inset-x-0 after:top-1/2 after:h-px after:bg-black/60">00</span>
  </div>
</div>
var box = document.getElementById('twct4');
function pad(n) { return String(n).padStart(2, '0'); }
function tick() { var now = new Date(), mid = new Date(now); mid.setHours(24, 0, 0, 0); var s = Math.floor((mid - now) / 1000), v = { h: Math.floor(s / 3600), m: Math.floor(s % 3600 / 60), s: s % 60 }; box.querySelectorAll('[data-u]').forEach(function (el) { el.textContent = pad(v[el.dataset.u]); }); }
tick(); setInterval(tick, 1000);

05. Tailwind Launch Countdown with Progress

TailwindCountdownProgress

A launch card showing days left and a progress bar from the announcement to launch day. The bar has role="progressbar" with its values set by the script, and the remaining time is also written out in words.

View code
<section class="w-full max-w-xs rounded-2xl bg-white p-5 shadow-sm ring-1 ring-slate-200">
  <p class="text-xs font-bold uppercase tracking-wider text-violet-700">Launching soon</p>
  <h3 class="mt-1 text-lg font-bold text-slate-900">Doors open in <span id="twct5d">3 days</span></h3>
  <div id="twct5b" role="progressbar" aria-label="Time until launch" aria-valuemin="0" aria-valuemax="100" class="mt-3 h-2.5 overflow-hidden rounded-full bg-slate-200"><div class="h-full rounded-full bg-violet-600" style="width:0"></div></div>
  <p id="twct5p" class="mt-1.5 text-xs text-slate-600"></p>
</section>
var start = Date.now() - 4 * 86400000, end = Date.now() + 3 * 86400000 - 3600000, bar = document.getElementById('twct5b');
function tick() { var now = Date.now(), p = Math.min(100, (now - start) / (end - start) * 100), left = Math.max(0, end - now), d = Math.floor(left / 86400000), h = Math.floor(left % 86400000 / 3600000);
  bar.firstElementChild.style.width = p + '%'; bar.setAttribute('aria-valuenow', Math.round(p)); document.getElementById('twct5d').textContent = d + ' days, ' + h + ' hours'; document.getElementById('twct5p').textContent = Math.round(p) + '% of the wait is over'; }
tick(); setInterval(tick, 60000);

06. Tailwind Resend Code Timer

TailwindCountdownForm

After sending a sign-in code, the Resend button stays disabled for 30 seconds and counts down in its own label, then becomes clickable. Using the disabled attribute means it really cannot be pressed early.

View code
<div class="w-full max-w-xs rounded-2xl bg-white p-5 text-center shadow-sm ring-1 ring-slate-200">
  <p class="text-sm text-slate-700">We sent a 6-digit code to <b class="text-slate-900">ana@example.com</b>.</p>
  <button id="twct6" type="button" disabled class="mt-3 rounded-lg bg-indigo-600 px-4 py-2 text-sm font-semibold text-white tabular-nums hover:bg-indigo-700 disabled:cursor-not-allowed disabled:bg-slate-200 disabled:text-slate-600 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600">Resend code in 0:30</button>
</div>
var b = document.getElementById('twct6'), n, t;
function run() { n = 30; b.disabled = true; b.textContent = 'Resend code in 0:30'; clearInterval(t); t = setInterval(function () { n--; if (n > 0) b.textContent = 'Resend code in 0:' + String(n).padStart(2, '0'); else { clearInterval(t); b.disabled = false; b.textContent = 'Resend code'; } }, 1000); }
b.onclick = run; run();

About these Tailwind Countdown Timers

Steady digits

tabular-nums gives every digit the same width, so the timer does not jitter as numbers change.

role="timer"

Timers are live regions that stay quiet by default, so a screen reader is not interrupted every second but can read the value on demand.

Compute from an end time

Store the target time and subtract the current time on every tick, instead of counting down a number, so the timer stays right even if the tab sleeps.

Say what happens at zero

Change the text or enable the action when time is up, as the resend button does, rather than leaving a row of zeros.

Frequently asked questions

Can I set a fixed date?

Yes. Replace the end time with new Date('2026-12-01T09:00:00Z').

Will the ring animate for reduced motion?

It still updates once a second but without the smooth transition.

Is there a CSS version?

Yes, see the CSS countdown timers collection.