ContentVidya UI/ Timer Widget
npm install @contentvidya/ui

Interactive Demo Playground

<timer-widget> Playground
⚙️ Configure Properties
Heading above the timer blocks.
ISO 8601 UTC date string to count down to (e.g. "2026-12-31T23:59:59Z").
Visual color theme for the timer blocks: "neon", "dark", or "gray".
Background image URL. When set, renders behind the widget with a readability overlay so timer blocks stay legible over photos.
CSS background-position for the background image.
CSS background for the scrim over the background image, e.g. a gradient or rgba() color.
Canvas background effect: "none", "particles", "waves", "rain", "thunderstorm", "sunrise", "sunset", "fog", "autumn", "festival", "santa", or "sea".
Message shown once targetDate has passed, in place of the countdown blocks.
CSS width for the root element.
CSS height for the root element. When 'auto' and backgroundImageUrl is set, height follows the image's natural aspect ratio.
Defer starting the countdown interval until scrolled near the viewport.
0.1
IntersectionObserver threshold, 0-1.
IntersectionObserver rootMargin.

Usage Code Generator

import TimerWidget from '@contentvidya/ui/react/TimerWidget';
import '@contentvidya/ui/theme.css';
// import { defaultBackgroundEffectPlugin } from '@contentvidya/ui/react/utils/backgroundEffects';
// Optionally override the canvas animation engine per-instance:
// backgroundEffectPlugin={{ start: myStart, stop: myStop }}

<TimerWidget
  title="Sale ends in:"
  targetDate="2026-12-31T23:59:59Z"
  variant="neon"
  backgroundImageUrl="/hero-sale.jpg"
  backgroundPosition="center"
  overlay="linear-gradient(to top, rgba(0,0,0,.7), rgba(0,0,0,.2))"
  backgroundEffect="particles"
  expiredText="This sale has ended — check back soon!"
  width="100%"
/>
<script lang="ts">
  import TimerWidget from '@contentvidya/ui/svelte/TimerWidget.svelte';
  // import { defaultBackgroundEffectPlugin } from '@contentvidya/ui/svelte/utils/backgroundEffects';
  // Optionally override the canvas animation engine per-instance:
  // backgroundEffectPlugin={{ start: myStart, stop: myStop }}
</script>

<TimerWidget
  title="Sale ends in:"
  targetDate="2026-12-31T23:59:59Z"
  variant="neon"
  backgroundImageUrl="/hero-sale.jpg"
  overlay="linear-gradient(to top, rgba(0,0,0,.7), rgba(0,0,0,.2))"
  backgroundEffect="particles"
  expiredText="This sale has ended — check back soon!"
/>
<script type="module"
  src="node_modules/@contentvidya/ui/webcomponents/TimerWidget.js"></script>

<!-- backgroundEffectPlugin ({ start, stop } functions) can't be passed as an
     HTML attribute string — set it as a JS property instead:
     document.querySelector('timer-widget').backgroundEffectPlugin = { start: myStart, stop: myStop }; -->
<timer-widget
  title="Sale ends in:"
  target-date="2026-12-31T23:59:59Z"
  variant="neon"
  background-image-url="/hero-sale.jpg"
  overlay="linear-gradient(to top, rgba(0,0,0,.7), rgba(0,0,0,.2))"
  background-effect="particles"
  expired-text="This sale has ended — check back soon!"
></timer-widget>

Props API Reference

PropTypeDefaultDescription
targetDate required string ISO 8601 date-time string; the countdown ticks towards this date
title string undefined Optional heading displayed above the timer blocks
variant 'neon' | 'dark' | 'gray' undefined Visual color theme for the timer blocks (default: 'dark')
backgroundImageUrl string undefined Background image URL. When set, renders behind the widget with a readability overlay so timer blocks stay legible over photos
backgroundPosition string undefined CSS background-position for the background image (default: 'center')
overlay string undefined CSS background for the scrim over the background image, e.g. a gradient or rgba() color (default: 'rgba(0, 0, 0, 0.45)')
backgroundEffect 'none' | 'particles' | 'waves' | 'rain' | 'thunderstorm' | 'sunrise' | 'sunset' | 'fog' | 'autumn' | 'festival' | 'santa' | 'sea' undefined Animated canvas layer rendered behind the timer blocks, from the same shared plugin engine (src/utils/backgroundEffects.ts) also used by Banner and SlidingBanner. Default: 'none'
backgroundEffectPlugin BackgroundEffectPlugin undefined Optional { start, stop } override for the canvas animation engine, letting a consumer (e.g. the CMS page editor) inject its own effect renderer per-instance instead of the built-in one. Falls back to defaultBackgroundEffectPlugin exported from src/utils/backgroundEffects.ts when omitted.
expiredText string undefined Message shown once targetDate has passed, in place of the countdown blocks
width string undefined CSS width for the root element (default: 'auto')
height string undefined CSS height for the root element (default: 'auto'). When 'auto' and backgroundImageUrl is set, the widget's height follows the image's natural aspect ratio via an in-flow . Pass an explicit value (e.g. '320px') to pin the height instead — the CMS admin computes and saves this from the image so the public page can reserve the space up front and avoid layout shift
className string undefined Additional CSS class names on the root element
lazyLoad boolean undefined Defer starting the countdown interval until scrolled near the viewport (default: true)
lazyThreshold number undefined IntersectionObserver threshold, 0-1 (default: 0.1)
lazyRootMargin string undefined IntersectionObserver rootMargin (default: '200px')
Past dates: When targetDate is in the past all values show 0, or expiredText if set. Update or remove the component via your CMS when the countdown expires.
SSR: The timer renders 0 on the server then hydrates on the client, avoiding any hydration mismatch.
Custom animation engine: Pass backgroundEffectPlugin={{ start, stop }} to swap the built-in canvas renderers for your own — useful for a CMS page editor that wants to inject a different animation implementation per-instance. Omit it to use the built-in defaultBackgroundEffectPlugin.
Background image: Set backgroundImageUrl to render a photo behind the countdown, with a legibility scrim controlled by overlay (any CSS background value — solid, rgba, or gradient). Leave height at its default 'auto' to let the widget follow the image's natural aspect ratio, or pin an explicit height (e.g. '320px') to avoid layout shift.
Background effects: Set backgroundEffect to 'particles', 'waves', 'rain', 'thunderstorm', 'sunrise', 'sunset', 'fog', 'autumn', 'festival', 'santa', or 'sea' to render an animated canvas layer behind the countdown — the same shared plugin engine (src/utils/backgroundEffects.ts) used by Banner and SlidingBanner. Combine with backgroundImageUrl and overlay for a photo backdrop with motion, or use it alone over the solid variant background.