Countdown
A countdown for a launch, the end of an offer or a weekly cut-off, written as one attribute that holds the date.
Documentation
-
Copy to Webflow
Add Geist and Geist Mono to your site's fonts (Site settings, Fonts, Google Fonts) before pasting: Webflow removes any font your site has not installed. -
Add custom CSS
Custom CSS in WebflowThis CSS already ships inside the Webflow embed, so a pasted section needs nothing added. Paste it yourself, in the page or the site custom code, only if the effect runs on several pages. The tutorial explains where.
See the tutorialThe look of the preview is thecountdown-*classes of the paste; the size of the figures is the font size of the box they are written in, a headline size for the box markeddata-countdown-lead, a text size in a banner. The Embed draws the columns and swaps the two states, and reads three variables with a fallback,--countdown-quiet(the units),--countdown-unit-size(their size against the figure, the same by default) and--countdown-gap(the room between two units): set them on the count, or on anything above it, in a rule of your own. The preview centres the count; the figures are text in a box, so the alignment is the text alignment of that box, left, centred or right. -
Add custom JS
Custom JavaScript in WebflowThis script already ships inside the Webflow embed, settings block included. You paste it yourself, before the closing body tag of the page or the site custom code, only when the effect has to run on several pages, and the tutorial says how to choose.
See the tutorial -
Use it on your own elements
How to add a custom attribute in WebflowA custom attribute is a pair, a name and a value, typed in the Settings panel of the element you selected, under Custom attributes. The name is what the script looks for, the value is what it reads. The tutorial shows the panel.
See the tutorialCustom attributesSelect the element on the canvas and open the Settings panel. Under Custom attributes, add a pair: the name on the left, the value on the right.Custom attribute What it does data-countdown Marks the box of a count, and its value is the date, written once: an ISO 8601 date with its offset, 2026-10-30T17:00:00-04:00, the same instant for every visitor. A date without offset is read on the clocks of data-countdown-zone. A time that really comes back is written 17:00, every day, or Fri 17:00, every week, with the zone. The settings below go on the same element. data-countdown-lead On a box inside the count. It takes no value. The engine writes in it the largest unit still running, with its word: 4 days, then 23 hours on the last day, 59 seconds in the last minute. Its text is what shows before the script, and on the Designer canvas: write the date in it. [ Optional ] data-countdown-rest On a box inside the count. It takes no value. The engine writes in it the units under the one written large, in one line. [ Optional ] data-countdown-time On a box inside the count. It takes no value. The engine writes every unit in it, in one line. With no box marked lead, rest or time, the box of the count itself is that line: a span in a sentence is enough. [ Optional ] data-countdown-local On a text inside the count. It takes no value. The engine rewrites it as the date in the visitor's own time zone and language. Its text is what shows without the script: write the date and its zone in it. [ Optional ] data-countdown-before On a block inside the count that leaves at zero. It takes no value. Put the boxes of the figures in it when there is a block for the end. [ Optional ] data-countdown-after On a block inside the count that waits for zero and takes the place of the first one. It takes no value. A page opened after the date shows it at once. On the Designer canvas, which runs no Embed, both blocks show, one under the other. [ Optional ] data-countdown-rehearse On a link, for a preview. Its value is a number of seconds: a click plays the count from that many seconds left, the count the link is in, or every count of the page when it is outside. Empty, it goes back to the date. Take these links out of a real page. [ Optional ] data-countdown-state Written by the engine on a mounted count: running, then done. data-countdown-ended is added when the end happened under the visitor's eyes, and data-countdown-ready once mounted. Never written by hand; the stylesheet reads them, and so can a rule of yours. [ Optional ] SettingsEvery setting is a custom attribute too, added the same way and on the same element. An attribute always wins over the defaults written in the code.Attribute Default What it is data-countdown-units days hours minutes seconds The units the count shows, largest first, parted by spaces. Options: any of days, hours, minutes, seconds. The largest one shown takes everything above it: without days, three days read 72 hours. The smallest one shown sets how often the figures change: without seconds, once a minute, and the count rounds up so it never shows zero before the end. data-countdown-labels short How a unit is written beside its figure, in the language of the page. Options: long (4 days, 6 hours), short (4 days, 6 hr, 12 min), narrow (4d 6h 12m). The box marked data-countdown-lead always takes the long word. data-countdown-zone empty The time zone of a date written without an offset, and of a time that comes back. Options: empty, for a date that carries its offset; or a name of the IANA list, America/New_York, Europe/Paris. Summer time is followed. data-countdown-locale empty The language the units are written in. Options: empty, the language of the page, read from the nearest lang attribute, then from the browser; or a tag, fr, de-CH, en-GB. data-countdown-done empty A word written where the figures were, at zero. Options: empty, and the figures stay at zero unless a block marked data-countdown-after takes their place; or a few words, Closed, We are open. data-countdown-roll 0.6 The time a column of seconds takes to turn, in seconds. Minutes take 1.25 times as long, hours 1.5, days 1.8.
Two files, no build step.
It runs in the browser only. Load it with a script tag in plain HTML, in a
client-side script in Astro, never in the frontmatter. In React, call
Countdown.mount(ref.current) in useEffect and
destroy() in its cleanup.
-
Tune it, either way
Per element with an attribute, or once for the whole site by editingDEFAULTSat the top of the file.Attribute Default What it is Lower Higher data-countdown-units days hours minutes seconds The units the count shows, largest first, parted by spaces. Options: any of days, hours, minutes, seconds. The largest one shown takes everything above it: without days, three days read 72 hours. The smallest one shown sets how often the figures change: without seconds, once a minute, and the count rounds up so it never shows zero before the end. data-countdown-labels short How a unit is written beside its figure, in the language of the page. Options: long (4 days, 6 hours), short (4 days, 6 hr, 12 min), narrow (4d 6h 12m). The box marked data-countdown-lead always takes the long word. data-countdown-zone empty The time zone of a date written without an offset, and of a time that comes back. Options: empty, for a date that carries its offset; or a name of the IANA list, America/New_York, Europe/Paris. Summer time is followed. data-countdown-locale empty The language the units are written in. Options: empty, the language of the page, read from the nearest lang attribute, then from the browser; or a tag, fr, de-CH, en-GB. data-countdown-done empty A word written where the figures were, at zero. Options: empty, and the figures stay at zero unless a block marked data-countdown-after takes their place; or a few words, Closed, We are open. data-countdown-roll 0.6 The time a column of seconds takes to turn, in seconds. Minutes take 1.25 times as long, hours 1.5, days 1.8. Snappier; 0 and the figures change with nothing turning Slower and softer; the engine stops at 0.9, so a column has landed before the next second -
Drive it from JavaScript
When a script sets the date, reacts to the end, or adds counts after the page has loaded.const element = document.querySelector('[data-countdown]'); element.addEventListener('countdown:done', (e) => { console.log(e.detail); }); // React to the end: unlock a button, load the new prices, reload. element.addEventListener('countdown:done', (event) => { console.log(event.detail.date, event.detail.live); // live: it ended under the visitor's eyes }); const count = Countdown.mount(element); // the box auto() mounted, or a new one count.left(); // milliseconds left, never below 0 count.set('2026-11-27T09:00:00+01:00'); // another date: from an API, a cart, a quote count.rehearse(5); // plays the last five seconds, to check the end count.rehearse(); // back to the date // When the count leaves the page: count.destroy(); // every box has its own text back, the date in clear
-
Fit it to your page
The stylesheet goes in the head and the script before the end of the body. The smallest count is one element in a sentence:
html <p>The sale ends in <span data-countdown="2026-10-30T17:00:00-04:00">October 30, 5 pm Eastern</span>.</p>The text of the element is what shows without the script, so write the date in it. The size of the figures is the font size of the box.
For a hero, the largest unit written large, the others under it, and a block for the end:
html <div data-countdown="2026-10-30T17:00:00-04:00" data-countdown-units="days hours minutes seconds"> <div data-countdown-before> <div data-countdown-lead>October 30</div> <div data-countdown-rest>5 pm Eastern</div> </div> <div data-countdown-after>The sale has ended.</div> <p data-countdown-local>Friday, October 30 at 5:00 pm Eastern</p> </div>The page hears the end, and each change of the figures:
`js element.addEventListener('countdown:done', (event) => { console.log(event.detail.date, event.detail.live); // live: it ended under the visitor's eyes });const count = Countdown.mount(element); count.left(); // milliseconds left, never below 0 count.set('2026-11-27T09:00:00+01:00'); // another date: from an API, a cart, a quote
`A deadline of the visitor's own. A hold on a cart, a quote valid 48 hours, a trial: the deadline is decided and kept by the server, which writes it in the attribute or hands it to
set(). The engine has no "so many minutes from the first visit" mode on purpose: kept in the browser, such a count starts again in a private window, and a deadline that restarts is a false one. Showing a false deadline to press a sale is an unfair commercial practice in the European Union and in the United Kingdom, and the kind of dark pattern the FTC acts against. A time that comes back,17:00orFri 17:00, is for what really comes back: the last collection of the day, the weekly truck. -
Avoid the pitfalls
- Write the offset.
2026-10-30T17:00:00-04:00, orZfor UTC. A date without offset and withoutdata-countdown-zoneis read as UTC, and the console says so. Never rely on the visitor's own clock for the zone. - A weekly or daily time needs its zone,
America/New_York: the engine finds the next one, summer time included. At zero the count ends like any other; the next load, orrefresh(), counts to the next one. - The marked boxes hold text only. The engine replaces what is in a box marked
data-countdown-lead,-rest,-timeor-local, and puts it back ondestroy(). When the count has none of the first three, the whole box is the line: keep its other content outside. - **Put the figures in the block marked
data-countdown-before** when there is a block for the end, so they leave together. - Tabular figures. The engine asks the font for them (
font-variant-numeric: tabular-nums). A display face without them lets the line breathe by a pixel as digits change. - Colours and sizes are custom properties read with a fallback:
--countdown-quietfor the units,--countdown-unit-sizefor their size against the figure (the same size by default,0.2emsets a small unit beside a large figure),--countdown-gapfor the room between two units. - Alignment is yours. The preview centres the count in the screen; that is its look, not the engine. The figures are text in a box:
text-alignon that box sets them left, centred or right. Every digit has the same width, so a centred line does not move as the seconds go by; when a column, a word or a unit leaves, its width closes over the time of its turn and the line recentres with it, never in one step. - Webflow CMS. In a Collection list or on a Collection page, the value of the custom attribute
data-countdowncan be bound to a field of the item. Bind it to a plain text field that holds the ISO date with its offset: text fields are what the binding is known to take. Whether the Designer offers a Date field there, and the format it would print, has not been verified; if it does, the engine reads what the browser'sDatereads and takes it on the clocks ofdata-countdown-zone, to be checked on the published page. - **The links marked
data-countdown-rehearse** belong to the preview, the row "Watch it pass" at the foot of the markup. The preview keeps it; on a page of your own, delete the row: nothing else reads it, and the counts go on as before.
- Write the offset.
One click on Copy the AI prompt copies everything an assistant needs to build this effect: the complete code, the markup, the dependency, every setting and every pitfall.
What it does
Countdown is a site utility component for Webflow and vanilla JavaScript, with no library. Also called countdown timer, launch countdown timer or sale countdown timer.
A countdown for a launch, the end of an offer or a weekly cut-off, written as one attribute that holds the date. The time left is read from the clock at every look, never counted, so it cannot drift: a tab left in the background, a laptop put to sleep or a system clock set again come back to the right figures at once, with nothing catching up digit by digit. Each character sits in a window of its own. A second turns one column, calmly; when a unit runs out, the carry goes up the line, one column after the other from the right, each heavier wheel turning a little slower, so the eye reads how rare the passage is from how far the movement travels: one column for a second, the whole line for a day. The page chooses where the figures go: one line for a banner or a sentence, or the largest unit still running written large with its word, 4 days, then 23 hours on the last day and 59 seconds in the last minute, with the other units in a small line under it. A unit that is spent leaves the line. At zero the figures leave, a block of the page takes their place or a word is written where they were, and an event fires; a page opened after the date shows the end at once, and nothing ever goes below zero. Units are written and accorded by the browser in the language of the page (1 day, 2 days, 1 jour, 3 Tage), figures are tabular so nothing moves sideways, a screen reader meets a timer it can read as a sentence and is never interrupted, and the end is said once. One timer serves every count of the page and a count off screen draws nothing. Without JavaScript the date stays written in clear. Reduced motion respected. No library. Pattern type countdown timer, launch countdown, sale timer, shipping cut-off.
Updated
Questions
Paste the block, or give any text block the custom attribute data-countdown with the date as its value, 2026-10-30T17:00:00-04:00, and add the Embed once. The text of the block is the date written in clear, which is what the Designer canvas and a visitor without JavaScript see; the published page counts.
Yes. A date written with its offset is one instant, so every visitor counts to it whatever their own clock says. A date without offset is read on the clocks of data-countdown-zone, America/New_York for instance, summer time included, and a text marked data-countdown-local is rewritten as the date in the visitor's own time.
A countdown that subtracts one from a number every setInterval drifts, because browsers slow timers in hidden tabs and stop them when a laptop sleeps. This one counts nothing: at every look it reads the clock and subtracts it from the date, so a tab that comes back shows the right figures at once, with nothing catching up digit by digit.
A block marked data-countdown-after takes the place of the one marked data-countdown-before, or data-countdown-done="Closed" writes a word where the figures were, and the event countdown:done fires. A page opened after the date shows that end at once, and the figures never go below zero.
Not with this one, on purpose: a deadline kept in the browser starts again in a private window, and showing a false deadline to press a sale is a banned commercial practice in the European Union and the United Kingdom. A time that really comes back is written 17:00 or Fri 17:00 with data-countdown-zone, and a deadline of the visitor's own comes from your server, in the attribute or through set().