Want a live, countdown without needing a schedule? This recipe drops a customizable timer anywhere. Set your date, time, tweak the colors, and watch it tick down to 0.

What you get

Setup

  1. Add a new shortcode (CMS Configuration > LAVA Shorcodes)
  2. Name: Countdown Timer
  3. Tag Name: countdowntimer
  4. Tag Type: Inline
  5. Description: Countdown timer to specified date and time. Customizable color.
  6. Documentation: Paste code below
  7. Shortcode Markup: Paste code below (adjust the defaults as needed)
  8. Parameters: date, time, color-background, color-font, color-number
  9. Enable Lava Commands: none

Documentation

    <p>This control displays a timer based on time left to goal date and time.</p>
    <h5>Example Usage</h5>
    <pre>{[ countdown timer date:'12/25/2030' time:'16:30' ]}</pre>
    <h5>Parameter List</h5>
    <p>This control supports the following parameters:</p>
    <ul>
        <li><b>date </b> - Target date. Formatted like this: 'mm/dd/yyyy'</li>
        <li><b>time </b> - Target time. Formatted in 24hr  military time: 'hh:mm'</li>
        <li><b>color-background </b>(hexcode)<b> </b>- Background color of the cards. Default is #149cd8.</li>
        <li><b>color-font </b> (hexcode) - Date/Time text color. Default is #000000.</li>
        <li><b>color-number</b> (hexcode) - Background color of the cards. Default is #ffffff.</li>
    </ul>

Markup

{%- assign targetStr = date | Append:' ' | Append:time -%}
{%- assign target = targetStr | Date:'MM/dd/yyyy h:mm' | AsDateTime -%}
{%- if target == null -%}
    <span>Invalid date/time format.</span>
{%- else -%}
    {%- assign now = 'Now' | Date | AsDateTime -%}
    {%- assign seconds = now | DateDiff:target,'s' -%}
    {%- if seconds < 0 -%}{%- assign seconds = 0 -%}{%- endif -%}
    {%- assign days = seconds | DividedBy:86400 | Floor -%}
    {%- assign hours = seconds | Modulo:86400 | DividedBy:3600 | Floor -%}
    {%- assign minutes = seconds | Modulo:3600 | DividedBy:60 | Floor -%}
    {%- assign seconds = seconds | Modulo:60 | Floor -%}
    {%- assign colorBackground = color-background | Default:'#149cd8' -%}
    {%- assign colorFont = color-font | Default:'black' -%}
    {%- assign colorNumber = color-number | Default:'white' -%}
<div class="countdown-timer" data-target="{{ target | Date:'yyyy-MM-ddTHH:mm:ss' }}" 
     style="display: flex; justify-content: center; gap: 15px; 
            font-family: Arial, sans-serif; max-width: 100%; 
            flex-wrap: wrap;">
    <div class="countdown-unit days">
        <div class="digit-box" style="background-color: {{ colorBackground }}; 
                color: {{ colorNumber }}; padding: 15px; 
                border-radius: 8px; text-align: center; 
                min-width: 80px; box-shadow: 0 4px 8px rgba(0,0,0,0.2);">
            <span class="value animated-value">{{ days | Format:'00' }}</span>
        </div>
        <div class="label" style="color: {{ colorFont }}; text-align: center; 
                font-size: 0.9em; margin-top: 5px;">Days</div>
    </div>
    <div class="countdown-unit hours">
        <div class="digit-box" style="background-color: {{ colorBackground }}; 
                color: {{ colorNumber }}; padding: 15px; 
                border-radius: 8px; text-align: center; 
                min-width: 80px; box-shadow: 0 4px 8px rgba(0,0,0,0.2);">
            <span class="value animated-value">{{ hours | Format:'00' }}</span>
        </div>
        <div class="label" style="color: {{ colorFont }}; text-align: center; 
                font-size: 0.9em; margin-top: 5px;">Hours</div>
    </div>
    <div class="countdown-unit minutes">
        <div class="digit-box" style="background-color: {{ colorBackground }}; 
                color: {{ colorNumber }}; padding: 15px; 
                border-radius: 8px; text-align: center; 
                min-width: 80px; box-shadow: 0 4px 8px rgba(0,0,0,0.2);">
            <span class="value animated-value">{{ minutes | Format:'00' }}</span>
        </div>
        <div class="label" style="color: {{ colorFont }}; text-align: center; 
                font-size: 0.9em; margin-top: 5px;">Minutes</div>
    </div>
    <div class="countdown-unit seconds">
        <div class="digit-box" style="background-color: {{ colorBackground }}; 
                color: {{ colorNumber }}; padding: 15px; 
                border-radius: 8px; text-align: center; 
                min-width: 80px; box-shadow: 0 4px 8px rgba(0,0,0,0.2);">
            <span class="value animated-value">{{ seconds | Format:'00' }}</span>
        </div>
        <div class="label" style="color: {{ colorFont }}; text-align: center; 
                font-size: 0.9em; margin-top: 5px;">Seconds</div>
    </div>
</div>
{%- stylesheet id:'countdown-timer-style' -%}
    .countdown-timer { font-size: 1.2em; padding: 10px; }
    .countdown-unit { text-align: center; min-width: 100px; }
    .digit-box { font-size: 2em; font-weight: bold; position: relative; 
                 overflow: hidden; perspective: 1000px; }
    .animated-value { display: inline-block; transition: transform 0.6s; 
                      transform-style: preserve-3d; }
    .digit-box.flip .animated-value {
        animation: flip 0.6s ease-in-out forwards;
    }
    @keyframes flip {
        0% { transform: rotateX(0deg); }
        50% { transform: rotateX(-90deg); }
        100% { transform: rotateX(0deg); }
    }
    @media (max-width: 768px) {
        .digit-box { font-size: 1.5em; padding: 10px; min-width: 60px; }
        .countdown-unit { min-width: 80px; }
    }
{%- endstylesheet -%}
{%- javascript id:'countdown-timer-script' disableanonymousfunction:'true' -%}
    class CountdownUtils {
        static getTimeDiff(targetDate) {
            const now = new Date();
            let diff = (new Date(targetDate) - now) / 1000;
            if (diff < 0) diff = 0;
            const days = Math.floor(diff / 86400);
            const hours = Math.floor((diff % 86400) / 3600);
            const minutes = Math.floor((diff % 3600) / 60);
            const seconds = Math.floor(diff % 60);
            return { days, hours, minutes, seconds };
        }
        static padNumber(num) {
            return num.toString().padStart(2, '0');
        }
    }
    class CountdownTimer {
        constructor(element) {
            this.element = element;
            this.target = this.element.dataset.target;
            this.units = {
                days: this.element.querySelector('.days .digit-box'),
                hours: this.element.querySelector('.hours .digit-box'),
                minutes: this.element.querySelector('.minutes .digit-box'),
                seconds: this.element.querySelector('.seconds .digit-box')
            };
            this.values = {
                days: this.units.days.querySelector('.value'),
                hours: this.units.hours.querySelector('.value'),
                minutes: this.units.minutes.querySelector('.value'),
                seconds: this.units.seconds.querySelector('.value')
            };
            this.update();
            this.interval = setInterval(() => this.update(), 1000);
        }
        update() {
            const { days, hours, minutes, seconds } = 
                CountdownUtils.getTimeDiff(this.target);
            const newValues = {
                days: CountdownUtils.padNumber(days),
                hours: CountdownUtils.padNumber(hours),
                minutes: CountdownUtils.padNumber(minutes),
                seconds: CountdownUtils.padNumber(seconds)
            };
            Object.keys(newValues).forEach((key) => {
                if (this.values[key].textContent !== newValues[key]) {
                    const box = this.units[key];
                    const value = this.values[key];
                    box.classList.add('flip');
                    setTimeout(() => {
                        value.textContent = newValues[key];
                    }, 300); // Update text at halfway point of 0.6s animation
                    setTimeout(() => {
                        box.classList.remove('flip');
                    }, 600); // Remove class after animation
                }
            });
        }
    }
    window.addEventListener('load', () => {
        document.querySelectorAll('.countdown-timer')
            .forEach(el => new CountdownTimer(el));
    });
{%- endjavascript -%}
{%- endif -%}