zero-hour
v1.3.1
Published
Tiny countdown Web Component. Registers <countdown-timer> that renders a configurable DD:HH:MM:SS countdown to a target date/time (optional UTC offset) and fires a done event at zero.
Maintainers
Readme
Demo
➠ Install
yarn add zero-hour➠ Import
// Registers <countdown-timer> via customElements.define(...)
import 'zero-hour';
// Optional helper: subscribe to `done` and apply stylesheets
import { initCountdownTimers } from 'zero-hour';➠ Usage
// After importing 'zero-hour', the element is registered.
// Then just place <countdown-timer> in your HTML (see below).HTML: default start (autostart=true)
<countdown-timer
digits-url="/sprites/digits.webp"
separator-url="/sprites/sep.webp"
date="2025-12-31"
time="23:59:59"
utc="+03:00"
></countdown-timer>JS: subscribe to completion + optional styles
import { initCountdownTimers } from 'zero-hour';
initCountdownTimers({
selector: 'countdown-timer',
onDone: (el) => {
// The component dispatches: el.dispatchEvent(new CustomEvent('done'))
// Note: if the timer is already complete (e.g. user opened the page after the target time),
// `initCountdownTimers` will call `onDone` immediately (catch-up).
el.classList.add('is-done');
},
// Optional styles:
// - CSSStyleSheet (constructable stylesheet)
// - string (e.g. imported via ?raw from your CSS/SCSS pipeline)
// stylesheet: myCssStyleSheet,
});JS: custom styles from ?raw (CSS/SCSS)
import { initCountdownTimers } from 'zero-hour';
import ZeroHourCss from './assets/scss/components/zero-hour.scss?raw';
initCountdownTimers({
stylesheet: ZeroHourCss,
});JS: default styles shipped with the package
import { initCountdownTimers, zeroHourCssText } from 'zero-hour';
// Option A: use the built-in CSS text export
initCountdownTimers({
stylesheet: zeroHourCssText,
});
// Option B: import the package CSS file as raw text (your bundler must support ?raw)
// import ZeroHourCss from 'zero-hour/zero-hour.css?raw';
// initCountdownTimers({ stylesheet: ZeroHourCss });JS: manual control (start/stop/reset)
const el = document.querySelector('countdown-timer');
// @ts-expect-error: methods exist on the custom element instance after import
el?.stop();
// @ts-expect-error
el?.reset();
// @ts-expect-error
el?.start();Units (units)
<countdown-timer
digits-url="/sprites/digits.webp"
separator-url="/sprites/sep.webp"
date="2025-12-31"
time="23:59:59"
utc="+03:00"
units="h:m:s"
></countdown-timer>➠ Options
| Option (attribute) | Type | Default | Description |
|:--------------------:|:-----------------------:|:------------:|:---------------------------------------------------------------------------------------------------------------------------------------------------------|
| digits-url | string | — | URL to the digits sprite sheet. Required for the graphical display (otherwise only a text fallback is updated in the a11y layer). |
| separator-url | string | null | URL to the separator sprite (e.g. a colon). If omitted, separators are hidden. |
| autostart | boolean | true | Auto-start on connect. Can be a boolean attribute (autostart) or a string (autostart="false"). |
| date | YYYY-MM-DD | — | Target date. Without date the timer resolves to zero. |
| time | HH:MM[:SS] | 00:00:00 | Target time. |
| utc | UTC±H[:MM] or ±H[:MM] | UTC+0 | UTC offset used to compute the target moment. Examples: utc="UTC+03:00", utc="UTC-5". |
| units | string | "d:h:m:s" | Visible groups pattern using d, h, m, s separated by : (e.g. "h:m:s"). Empty/invalid value falls back to showing all. |
➠ API Methods
| Method | Description |
|-------------------|--------------------------------------------------------------------------------------------------|
| initCountdownTimers({ selector?, onDone?, stylesheet? }): HTMLElement[] | Finds elements by selector (default: countdown-timer), subscribes to the done event (when onDone is provided), and calls onDone immediately if a timer is already complete at init time (catch-up). Also optionally applies styles to each element (stylesheet?: CSSStyleSheet \| string \| null). When a string is provided, it is applied via adoptedStyleSheets when supported, otherwise via a <style> fallback inside the shadow root. |
| start(): void | Starts/restarts the countdown (only runs when digits-url is set). |
| stop(): void | Stops the timer and clears the scheduled tick. |
| reset(): void | Clears the “done fired” flag and either starts again (if autostart=true) or renders a static initial value. |
| isRunning(): boolean | Returns true if the timer is running and the next tick is scheduled. |
| isDone(): boolean | Returns true if the computed target moment is in the past (logically complete), regardless of whether a done event listener was attached in time. |
| adoptStylesheet(sheet: CSSStyleSheet): void | Replaces adoptedStyleSheets inside the component’s shadow root. |
➠ Notes
- Updates tick exactly on second boundaries (schedules the next tick to the next full second) to keep the display stable.
- Days render as two digits and are capped at 99.
unitscontrols which groups (d/h/m/s) are visible. Separators are auto-hidden whenseparator-urlis not set, or when a separator is not needed between visible groups.- The
doneevent fires once per run (afterreset()it can fire again). - Digit sprite must be horizontal, frames left-to-right:
0,1,2,3,4,5,6,7,8,9. The frame index equals the digit.
➠ License
zero-hour is released under MIT license
