22 CSS Countdown Timers

A countdown timer counts DOWN toward a deadline and drives a decision — buy before the sale ends, extend before the session expires, act before the seat closes. These 22 hand-coded patterns cover the accessible <time> reference build, session timeout warnings, OTP and rate-limit cooldowns, auction anti-snipe extension, delivery ETA, exam thresholds, cart expiry, queue position, and the classic flash-sale and flip-clock surfaces. Every timer recomputes from Date.now() each tick so it survives background-tab throttling, guards at zero instead of rendering negative time, and announces via aria-live at thresholds. Scoped under .cdt-NN; drops into React, Vue, Svelte, or Astro.

8 pure CSS14 light JSPublished 16 new designs · Updated on

Related25 CSS Number Counter Animations22 CSS Progress Bars20 CSS Banners & Alerts

Accessible Countdown with Time Element and ARIA — preview
01 / 22Light JSNEW

Accessible Countdown with Time Element and ARIA

The reference accessible countdown: a semantic time element carries the machine-readable deadline, role=timer marks the display, and a polite live region announces only at the hour, ten-minute, one-minute and expiry boundaries instead of shouting every second. An annotation panel labels each attribute so you can see why the quiet version is the usable one.

Published

Pure CSS Countdown Timer Without JavaScript — preview
02 / 22Pure CSSNEW

Pure CSS Countdown Timer Without JavaScript

A countdown that runs with zero script: a registered integer custom property is animated over a wall-clock duration and printed through counter-reset plus content: counter(). It is honest about the one thing it cannot do — it measures a duration from render, not the distance to a timestamp, so it suits session and quiz clocks, never a dated sale.

Published

Session Timeout Warning with Extend Action — preview
03 / 22Light JSNEW

Session Timeout Warning with Extend Action

The idle-timeout warning banks and health portals ship: after inactivity a native dialog opens with a running countdown, a Stay signed in action and an explicit Sign out now. Escape is deliberately not a dismissal, focus lands on the primary action, and the extend path is what makes a hard time limit pass WCAG 2.2.1.

Published

Circular Depleting Ring Countdown Timer — preview
04 / 22Pure CSSNEW

Circular Depleting Ring Countdown Timer

An SVG ring that empties as time runs out, not one that fills as a task completes. pathLength="100" turns the circumference into a percentage so stroke-dashoffset animates 0 to 100 with no circumference maths, and color-mix shifts the stroke through amber and red as the 50% and 20% marks pass.

Published

OTP Resend Cooldown Timer Button — preview
05 / 22Light JSNEW

OTP Resend Cooldown Timer Button

The resend cooldown every auth flow needs: after a one-time code is sent the resend control goes disabled with an inline countdown, then re-enables itself. The live region stays silent through the count and speaks once when the button becomes usable again, which is the only moment a screen-reader user needs to hear about.

Published

Rate Limit Cooldown Button with Retry Timer — preview
06 / 22Light JSNEW

Rate Limit Cooldown Button with Retry Timer

What a 429 should look like in a UI: the action returns Too Many Requests, the button enters a cooldown derived from the Retry-After header, and a tinted fill drains across the label as the seconds tick away. The response headers sit beside it so the number on the button is traceable to the value the server sent.

Published

Auction Ending Countdown with Anti Snipe — preview
07 / 22Light JSNEW

Auction Ending Countdown with Anti Snipe

A lot card whose countdown turns red under a minute and, when a bid lands in the closing seconds, visibly extends by two minutes with an Extended +2:00 flash. That soft-close rule is what keeps a last-second snipe from deciding the sale, and it is the one countdown where a real-time exemption to adjustable timing genuinely applies.

Published

Delivery ETA Countdown with Live Status — preview
08 / 22Pure CSSNEW

Delivery ETA Countdown with Live Status

An order-tracking ETA that counts down beside a four-step status rail, with the active step pulsing. The detail most implementations miss is the zero state: instead of drifting into negative minutes it flips to Arriving any moment, because a courier who is two minutes late should not make the interface look broken.

Published

Product Launch Waitlist Countdown Page — preview
09 / 22Pure CSSNEW

Product Launch Waitlist Countdown Page

A launch page built around the conversion surface rather than the clock: email capture first, a referral position chip that shows what moving up the queue is worth, and the countdown as supporting chrome under it. Glass panels over a violet-cyan field, and every number is a time-remaining value, never a counter climbing to a target.

Published

Webinar Registration Countdown with Timezone — preview
10 / 22Light JSNEW

Webinar Registration Countdown with Timezone

A registration card that counts down to the session and states the start time twice: once in the visitor's own timezone, resolved from the browser, and once in the host's. It also explains the parsing bug that silently shifts an event by hours for every visitor who is not in the author's timezone.

Published

Appointment Reminder Countdown Card — preview
11 / 22Pure CSSNEW

Appointment Reminder Countdown Card

An upcoming-visit card that changes precision as the appointment approaches: days and hours while it is far off, hours and minutes inside the last day, and the Reschedule and Cancel actions surfaced only once that switch happens. Two states are shown side by side so the transition is visible rather than described.

Published

Exam Time Remaining with Warning Thresholds — preview
12 / 22Light JSNEW

Exam Time Remaining with Warning Thresholds

A proctored-test time chip that changes state at 50%, 10% and 2% of the window remaining — colour, weight, icon and a single announcement at each boundary. It also ships the affordance most exam timers omit: a documented way to add time, because a timed assessment without an extension path locks out the students who need one.

Published

Subscription Trial Expiry Countdown Banner — preview
13 / 22Pure CSSNEW

Subscription Trial Expiry Countdown Banner

An in-app trial banner that escalates as the window closes: a calm purple state with seven days left, a magenta critical state inside the last two days, and a depleting bar in both. Dismissal is a checkbox and a :has() rule, so it costs no script — and this is an authenticated surface, not a site-wide promo bar.

Published

Maintenance Window Countdown Status Page — preview
14 / 22Pure CSSNEW

Maintenance Window Countdown Status Page

A scheduled-maintenance card that counts down to the window opening and then, at the moment it opens, flips to counting down to the window closing. The affected-services list sits beside it with per-service impact, because during a window the only question anyone actually has is which parts still work.

Published

Ticket Queue Position and Wait Countdown — preview
15 / 22Light JSNEW

Ticket Queue Position and Wait Countdown

A virtual waiting room: your place in line as the largest thing on the screen, an estimated wait counting down beneath it, and a reassurance line telling you not to refresh — because refreshing is the one action that costs a user their place, and it is exactly what an unexplained blank wait invites.

Published

Daily Streak Reset Countdown Widget — preview
16 / 22Light JSNEW

Daily Streak Reset Countdown Widget

A habit-app streak widget counting down to local midnight, with a flame that dims as the window closes. It computes the day boundary the way that survives daylight saving — by constructing tomorrow's date at hour zero rather than adding 24 hours — which is the bug that silently breaks streak apps twice a year.

Published

Flash Sale Countdown for Product Pages — preview
17 / 22Light JS

Flash Sale Countdown for Product Pages

A product-page urgency block: sale price against a struck original, a savings chip, the countdown to the sale ending and a stock-remaining bar in the same frame. At zero it does not vanish or freeze — it switches to a Sale ended state with the full price restored, which is the honest version of this pattern.

PublishedUpdated

Sticky Announcement Bar Countdown — preview
18 / 22Light JS

Sticky Announcement Bar Countdown

A site-wide sticky bar where the timer, not the message, is the dominant element: oversized tabular digits, one short line of offer copy, a compact CTA and a real dismiss control. It sticks to the top of the scroll container, collapses to a two-line layout on narrow screens and states its own end condition.

PublishedUpdated

Shopping Cart Expiration Countdown Timer — preview
19 / 22Light JS

Shopping Cart Expiration Countdown Timer

A cart-page reservation timer: items held for a fixed window, a per-line list of what is reserved, a warning state inside the last two minutes and an extend control. The rule it demonstrates is the one stores get wrong — never silently empty a cart; warn, offer more time, and say what happens if the window closes.

PublishedUpdated

Coming Soon Launch Page Countdown — preview
20 / 22Light JS

Coming Soon Launch Page Countdown

The classic pre-launch splash, rebuilt: a brand mark, one headline, four unit blocks for days, hours, minutes and seconds, and a single email field. Where most versions stall at zero, this one flips the whole page to a live state, because the day the countdown ends is the day the page has to still make sense.

PublishedUpdated

Circular Activity Timer for SaaS and Fitness — preview
21 / 22Pure CSS

Circular Activity Timer for SaaS and Fitness

An interval session timer with a depleting ring, Work and Rest phase labels, and a play-pause control that runs entirely on CSS: a checkbox flips animation-play-state, so the ring, the digits and the phase label all freeze and resume together with no script holding state.

PublishedUpdated

Retro Flip Clock Countdown Timer — preview
22 / 22Light JS

Retro Flip Clock Countdown Timer

A split-flap countdown with the hinge line down the middle of each card and a real flap rotation on every change. It is framed as a deadline mechanism — the last posting time for a print run — rather than a decorative odometer, and under reduced motion the flaps settle instantly while still showing the correct digit.

PublishedUpdated

FAQ

Frequently asked questions

Why does my countdown timer drift or freeze in a background tab?
Because setInterval(fn, 1000) is a request, not a guarantee. Browsers throttle timers in background tabs — Chrome clamps them to roughly once per minute after a few minutes hidden, and mobile Safari can suspend them entirely — so a timer that increments a counter each tick silently loses minutes. Even in the foreground, each tick carries a few milliseconds of scheduling error that accumulates: an hour-long timer drifts several seconds. The fix is to never count ticks. Store an absolute target timestamp once, then recompute the remaining time from Date.now() on every tick, so any missed or delayed ticks self-correct the moment the tab wakes. Schedule the next tick aligned to the next whole second with setTimeout(tick, 1000 - (Date.now() % 1000)) rather than a fixed 1000ms interval, which keeps the visible digit flipping on the second boundary instead of sliding. Every JavaScript demo in this collection uses that pattern. Pair it with document.visibilitychange if you also need to re-render immediately on tab focus rather than waiting up to a second.
How do I make a countdown timer accessible to screen readers?
The mistake almost every implementation makes is wrapping the digits in aria-live="polite" and letting it announce every second. That produces a continuous stream of interruptions that makes the rest of the page unusable with a screen reader — users routinely abandon a page that does it. Announce at meaningful thresholds instead: one hour, ten minutes, one minute, and expiry. Keep the visual digits outside the live region entirely and put a short sentence inside it that only changes when a threshold is crossed. Wrap the deadline in <time datetime="2026-12-31T23:59:59Z"> so the machine-readable target lives in the markup rather than only in script, and put role="timer" on the container so assistive technology knows what the region is. Give the compact digit display a visually-hidden full-sentence label — "2 hours 14 minutes remaining" — because 04:19:22 read aloud character by character is meaningless. Demo 01 is the reference implementation with an annotation panel labelling each attribute and the reasoning.
Can you build a countdown timer with only CSS and no JavaScript?
Partially, and the limitation matters. Registering a typed custom property with @property --t { syntax: '<integer>'; initial-value: 0; inherits: false } lets you animate an integer, and counter-reset plus content: counter() renders it as visible digits — a genuine countdown with zero script. What CSS cannot do is target an absolute moment in time. The animation starts when the element renders, so it measures a duration from page load, not the distance to a calendar date. That makes it correct for anything anchored to arrival — a quiz clock, a session timer, a five-minute hold — and wrong for anything anchored to a fixed deadline, because a visitor arriving an hour before your sale ends sees the same numbers as one arriving a week early. It also resets on refresh and cannot survive navigation. Demo 02 ships the pattern with that limitation stated in the demo chrome itself rather than buried in documentation, because a pure-CSS countdown that silently lies about a sale deadline is worse than no countdown.
What does WCAG 2.2.1 require for session timeouts and timed tests?
Success Criterion 2.2.1 (Timing Adjustable, Level A) says that when a time limit is set by the content, the user must be able to turn it off, adjust it to at least ten times the default, or extend it — with at least twenty seconds' warning and a simple action like pressing a key. A session that expires silently, or a warning modal that gives five seconds to react, fails at Level A. Practically that means a timeout warning needs to appear well before expiry, be announced through role="alertdialog" so it interrupts appropriately, move focus to the primary action, and offer an extend control. Escape should not dismiss it — a timeout warning is a question that has to be answered, and dismissing it silently returns the user to a page that is about to log them out. The criterion carves out real-time exceptions where extending would invalidate the activity: a live auction close and a queue position genuinely cannot be extended per-user, and those demos document the exemption instead of pretending to offer one. Demos 03, 12 and 19 ship extend affordances; 07 and 15 document the exception.
How do I show a deadline correctly across timezones?
Two failures cause most timezone bugs. The first is parsing: new Date("2026-09-01 14:00") is parsed as local time in every browser, so the same string resolves to a different absolute moment for every visitor — your Berlin event silently starts at 14:00 in Denver too. Always store and parse the deadline as an ISO 8601 string with an explicit offset or trailing Z, which is unambiguous everywhere. The second is display: showing only the host timezone forces every visitor to do the conversion in their head, and they get it wrong. Read the visitor's zone with Intl.DateTimeFormat().resolvedOptions().timeZone and render the deadline in it as the primary line, with the host timezone as a secondary line so people coordinating across regions can still reconcile. Use Intl.RelativeTimeFormat for the "in 2 days" phrasing rather than hand-rolled string math, because it handles pluralisation and locale rules you would otherwise get wrong. Demo 10 ships all of this for a webinar registration surface.
What happens when the countdown reaches zero?
It must switch to a terminal state, never render negative time. A timer showing -00:14 is the clearest possible signal that nobody tested past the deadline, and it appears constantly in production because the tick function keeps subtracting after the target passes. Guard before you compute digits: either clamp with Math.max(0, target - Date.now()), or return early into an explicit end state as soon as the remaining time hits zero. The terminal state itself should be meaningful rather than a row of zeroes — "Sale ended", "Session expired", "Arriving any moment". That last one matters for delivery and ETA surfaces, where passing the estimate is normal and showing negative time reads as a system failure rather than a late courier. Also stop the timer: clear the pending setTimeout so it does not keep firing against an expired target, and make sure the cleanup runs on unmount so a single-page app does not accumulate orphaned timers on every route change. Every JavaScript demo here exposes a cleanup function for exactly that reason.
How is this different from the number counter and banner collections?
Three collections sit adjacent and each owns a distinct behaviour. This collection covers timers that count DOWN toward a deadline and drive a decision — buy before the sale ends, extend before the session expires, act before the seat closes. css-number-counter-animations (25 demos) owns numbers that count UP toward a target: stats, KPIs, milestones, odometers, live tickers. If the number is celebrating a total rather than pressuring a deadline, that is the collection you want. css-banners-alerts (20 demos) owns the site-wide banner as a component — cookie consent, maintenance notice, promo bar — where the bar is the subject and any timer inside it is supporting chrome; here the timer is the subject. css-progress-bars (22 demos) owns determinate progress as a value indicator: upload percentage, storage used, form step. A depleting ring in this collection represents time remaining, not task completion, which is why demo 04 is framed as depletion rather than progress.
How portable are these timers across React, Vue, Svelte, and Astro?
Every demo is framework-agnostic HTML and CSS with at most thirty lines of vanilla JavaScript, scoped under a unique .cdt-NN root so nothing leaks into a host page. The one thing that needs attention in any framework is cleanup: each timer holds a pending setTimeout that must be cancelled when the component unmounts, or an app accumulates orphaned timers across route changes and eventually fires callbacks against detached DOM. In React the tick logic goes in a useEffect whose cleanup return calls clearTimeout; Vue uses onMounted and onUnmounted; Svelte uses onMount returning a teardown; Angular clears in ngOnDestroy. Each demo exposes its cleanup as a function on the root element so the wiring is a one-liner. In Astro the pure-CSS demos render as static HTML with no island at all, and the JavaScript ones hydrate with client:visible. Tailwind users can lift the rules into @layer components on v3, or declare the same tokens in @theme on v4 so utilities and demo CSS share one source.

Related collections

30 CSS Badges preview

30 CSS Badges

30 hand-coded CSS badges for status indicators, notifications, membership tiers, live-data displays, and SEO / DevOps / financial dashboards — upload progress, typing indicator, transit line status, Core Web Vitals, ECG heartbeat, CI/CD build pipeline, countdown ring, live price ticker, keycap shortcut, wax seal, conference lanyard, and holographic collectibles. Copy-paste HTML and CSS, WCAG 2.2 accessible, MIT licensed.

20 CSS Banners & Alerts preview

20 CSS Banners & Alerts

20 hand-coded CSS banner and alert bars for e-commerce storefronts, SaaS dashboards, marketing sites, and compliance-bound products. Covers GDPR cookie consent with a real preferences panel, promo bars with countdown timers, free-shipping threshold progress, app-install smart banners, maintenance and incident status bars, newsletter signup bars, age verification gates, limited-stock urgency banners, live event announcements, browser upgrade notices, geo and currency switchers, sticky top announcement bars, bottom cookie bars, inline form validation alerts, icon-aligned alert banners, left-border accent alerts, diagonal stripe promos, full-width hero banners, animated gradient border alerts, and a text-wrapping laboratory that shows five strategies for the unbreakable string that breaks more banners than anything else. Every bar is scoped under a .ba-NN prefix for no-collision pasting, guards prefers-reduced-motion, carries the correct aria-live and role semantics, and ports unchanged to React, Vue, Svelte, Astro, Next.js and Tailwind.

25 CSS Blockquotes preview

25 CSS Blockquotes

25 hand-coded CSS blockquote designs for SaaS testimonials, editorial pull quotes, documentation callouts, and developer engineering blogs: large decorative quotation marks with ::before / ::after glyphs, Tailwind CSS blockquote component, pure CSS callout / admonition boxes for Docusaurus / Mintlify / Nextra documentation, responsive center-aligned quote banners, modern minimalist left-border editorial style, animated CSS gradient border, classic left border, brutalist high-contrast, glassmorphism frosted card, glowing neon border, article pull quote with text-wrap, speech bubble chat-style, thick vertical accent rail, customer testimonial cards with avatar and star rating, inline highlighted text, marker highlight underline, floating drop-shadow, aurora gradient background, Twitter / X card style, multi-column newspaper editorial, IDE code-comment style, Markdown-compatible defaults, JavaScript testimonial quote slider, expandable read-more, and one-click copy button. 22 Pure CSS + 3 Light JS (slider, expand, copy). Every design scoped under .bq-NN prefix for no-collision pasting, prefers-reduced-motion guarded per WCAG 2.3.3, WCAG 2.2 AA accessible, framework-agnostic (React, Vue, Svelte, Astro, Next.js, Nuxt, Remix, SvelteKit).

Search CodeFronts

Loading…