0 Pure CSS7 with JSPublished 2026-10-05Free · no sign-up
Seven countdowns: boxes for days, hours, minutes and seconds, digits that slide as they change, rings that empty, a countdown inside a sentence, a sale banner that retires itself, a quiz timer with a pause button and a minimal launch countdown.
Four boxes counting down to an end time three days from when the page loads. The end time is also written as a time element, which is what screen readers and search engines use; the ticking boxes are a role="timer" region, which is not announced every second.
var end = new Date(Date.now() + 3 * 864e5 + 5 * 36e5), t = document.querySelector('.cd1 time');
t.dateTime = end.toISOString(); t.textContent = end.toLocaleString('en-GB', { weekday: 'short', day: 'numeric', month: 'short', hour: '2-digit', minute: '2-digit' });
function pad(n) { return String(n).padStart(2, '0'); }
(function tick() { var s = Math.max(0, Math.floor((end - Date.now()) / 1000));
document.querySelector('.cd1 .d').textContent = pad(Math.floor(s / 86400)); document.querySelector('.cd1 .h').textContent = pad(Math.floor(s % 86400 / 3600));
document.querySelector('.cd1 .m').textContent = pad(Math.floor(s % 3600 / 60)); document.querySelector('.cd1 .s').textContent = pad(s % 60);
if (s > 0) setTimeout(tick, 1000); })();
02. Digits That Slide on Change
CountdownAnimation
Each time a digit changes it slides up out of view and the new one slides in, a softer cousin of the flip clock. Only the digits that changed animate, by restarting a keyframe on that one element, and reduced motion swaps them instantly.
View code
<div class="cd2" role="timer" aria-label="Minutes and seconds left"><span class="u"><i>0</i><i>5</i></span><b>:</b><span class="u"><i>0</i><i>0</i></span></div>
var digits = document.querySelectorAll('.cd2 i'), left = 300;
setInterval(function () { if (left <= 0) return; left--; var str = String(Math.floor(left / 60)).padStart(2, '0') + String(left % 60).padStart(2, '0');
digits.forEach(function (d, k) { if (d.textContent !== str[k]) { d.textContent = str[k]; d.classList.remove('go'); void d.offsetWidth; d.classList.add('go'); } }); }, 1000);
03. Countdown Rings
CountdownRings
Hours, minutes and seconds each shown as a ring that empties as time passes, drawn with conic gradients whose fill comes from a custom property. The numbers sit in the middle of each ring and the group is a timer region.
var end = Date.now() + (5 * 3600 + 42 * 60 + 18) * 1000, ps = document.querySelectorAll('.cd3 p');
(function tick() { var s = Math.max(0, Math.floor((end - Date.now()) / 1000)), v = [Math.floor(s / 3600), Math.floor(s % 3600 / 60), s % 60], max = [24, 60, 60];
ps.forEach(function (p, k) { p.style.setProperty('--p', v[k] / max[k] * 100); p.querySelector('b').textContent = String(v[k]).padStart(2, '0'); });
if (s > 0) setTimeout(tick, 1000); })();
04. Inline Countdown in a Sentence
CountdownInline
A countdown that sits inside a line of text, like Order within 2h 14m for delivery tomorrow, which is often more persuasive than a giant clock. It updates once a minute rather than every second, which is all this kind of message needs.
View code
<p class="cd4">Order within <strong class="t" role="timer">2h 14m</strong> for delivery <b>tomorrow</b>.</p>
var end = Date.now() + (2 * 60 + 14) * 60000, t = document.querySelector('.cd4 .t');
(function tick() { var m = Math.max(0, Math.ceil((end - Date.now()) / 60000)); t.textContent = Math.floor(m / 60) + 'h ' + (m % 60) + 'm'; if (m > 0) setTimeout(tick, 60000); })();
05. Sale Banner with Countdown
CountdownBanner
A slim promotional banner with the offer, a compact HH:MM:SS countdown and a link. When the time runs out, the banner changes its own text to say the sale has ended instead of showing zeros, so it never shows an expired offer.
var w = document.querySelector('.cd5'), t = w.querySelector('.t'), end = Date.now() + (6 * 3600 + 3 * 60 + 9) * 1000;
(function tick() { var s = Math.floor((end - Date.now()) / 1000); if (s <= 0) { w.innerHTML = '<p>The 24-hour sale has ended. Thanks for shopping.</p>'; return; }
t.textContent = [Math.floor(s / 3600), Math.floor(s % 3600 / 60), s % 60].map(function (n) { return String(n).padStart(2, '0'); }).join(':'); setTimeout(tick, 1000); })();
06. Quiz Timer with Pause
CountdownProgress
A 30-second timer for a quiz question with a draining bar and a Pause button, because timed tasks must let people pause or extend them under WCAG. The remaining time is announced only at 10 seconds and at the end, not every tick.
var w = document.querySelector('.cd6'), bar = w.querySelector('.bar span'), t = w.querySelector('.t'), b = w.querySelector('button'), live = w.querySelector('.sr'), left = 30, paused = false;
var id = setInterval(function () { if (paused || left <= 0) return; left--; t.textContent = left; bar.style.transform = 'scaleX(' + left / 30 + ')';
if (left === 10) live.textContent = '10 seconds left'; if (left === 0) { live.textContent = 'Time is up'; b.disabled = true; clearInterval(id); } }, 1000);
b.onclick = function () { paused = !paused; b.setAttribute('aria-pressed', paused); b.textContent = paused ? 'Resume' : 'Pause'; };
07. Minimal Launch Countdown
CountdownLaunch
A big, quiet countdown for a launch page: large thin numbers, small labels and a sign-up link underneath. The launch date is a real time element in the heading, so the page still makes sense if the script never runs.
View code
<section class="cd7"><h3>Launching <time datetime="2026-12-01">1 December 2026</time></h3><div role="timer" aria-label="Time until launch"><span><b class="d">--</b>days</span><span><b class="h">--</b>hours</span><span><b class="m">--</b>minutes</span></div><a href="#notify">Get notified</a></section>
var end = new Date('2026-12-01T09:00:00Z').getTime();
(function tick() { var s = Math.max(0, Math.floor((end - Date.now()) / 1000));
document.querySelector('.cd7 .d').textContent = Math.floor(s / 86400); document.querySelector('.cd7 .h').textContent = String(Math.floor(s % 86400 / 3600)).padStart(2, '0'); document.querySelector('.cd7 .m').textContent = String(Math.floor(s % 3600 / 60)).padStart(2, '0');
if (s > 0) setTimeout(tick, 30000); })();
About these CSS Countdown Timers
Do not announce every second
A ticking number read aloud every second is unbearable. Put the countdown in a role="timer" element, which is not announced by default, and announce only meaningful moments such as 10 seconds left.
Write the end time down
Show the deadline as a real <time datetime> too, such as Ends Friday 18:00. It is useful to everyone, readable by assistive technology and still correct if the script fails.
Timed tasks need a pause
WCAG asks that people can pause, stop or extend time limits. A quiz or checkout timer needs a Pause or More time button.
Handle the end
When the countdown reaches zero, change the message: The sale has ended. Never leave a banner showing 00:00:00 or an offer that no longer exists.
Frequently asked questions
Are fake urgency timers OK?
No. A countdown that resets on every visit misleads buyers and breaks consumer law in many places. Count to a real deadline.
Which time zone do the timers use?
They count to an absolute moment, so every visitor sees the right time left wherever they are.
Will the timer drift?
Each tick recalculates from the end time rather than subtracting a second, so it stays accurate.