FreeAnnouncement Bars

Countdown Announcement Bar

Live countdown bar with dismiss + CTA. Header-group ready.

#announcement-bar#countdown#urgency#header

Live preview

See it in action.

Fully interactive, drag, click, scroll inside the frame, toggle to mobile.

About this section

Top-of-page announcement with a real-time countdown to a configurable end date. Dismissed-state persists per visitor via localStorage. Lives in the header section group.

Install in 90 seconds

  1. 01

    Create /sections/modblo-countdown-announcement.liquid.

  2. 02

    Paste the code and save.

  3. 03

    In the theme editor, add it to the Header section group at the top.

The Liquid

modblo-countdown-announcement.liquid
{%- comment -%} modblo. Countdown Announcement Bar {%- endcomment -%}
<div class="modblo-cd" data-section-id="{{ section.id }}" data-modblo-cd
     data-end="{{ section.settings.end_date }}T{{ section.settings.end_time | default: '23:59' }}"
     style="--modblo-bg: {{ section.settings.bg }}; --modblo-fg: {{ section.settings.fg }}; --modblo-accent: {{ section.settings.accent }};"
     {% if section.settings.dismissible %}data-dismissible="true"{% endif %}>
  <div class="modblo-cd__inner">
    {%- if section.settings.message != blank -%}
      <span class="modblo-cd__msg">{{ section.settings.message }}</span>
    {%- endif -%}
    <span class="modblo-cd__timer" aria-live="polite">
      <span data-d>00</span><i>d</i>
      <span data-h>00</span><i>h</i>
      <span data-m>00</span><i>m</i>
      <span data-s>00</span><i>s</i>
    </span>
    {%- if section.settings.cta_label != blank -%}
      <a class="modblo-cd__cta" href="{{ section.settings.cta_link }}">
        {{ section.settings.cta_label }} →
      </a>
    {%- endif -%}
    {%- if section.settings.dismissible -%}
      <button type="button" class="modblo-cd__close" aria-label="Dismiss" data-close>×</button>
    {%- endif -%}
  </div>
</div>

<style>
  .modblo-cd {
    background: var(--modblo-bg, #0b0b0c); color: var(--modblo-fg, #fff);
    border-bottom: 1px solid color-mix(in oklab, var(--modblo-fg) 12%, transparent);
    font-size: 13px;
  }
  .modblo-cd[hidden] { display: none; }
  .modblo-cd__inner {
    max-width: 1200px; margin: 0 auto; padding: 10px 24px;
    display: flex; align-items: center; gap: 16px; justify-content: center;
    flex-wrap: wrap;
  }
  .modblo-cd__msg { font-weight: 500; }
  .modblo-cd__timer {
    font-variant-numeric: tabular-nums; display: inline-flex; gap: 2px;
    font-weight: 600;
    background: color-mix(in oklab, var(--modblo-fg) 8%, transparent);
    border-radius: 999px; padding: 4px 12px;
  }
  .modblo-cd__timer i { opacity: .55; font-style: normal; margin-right: 6px; }
  .modblo-cd__timer i:last-child { margin-right: 0; }
  .modblo-cd__cta {
    color: var(--modblo-accent, #fff); text-decoration: none; font-weight: 600;
  }
  .modblo-cd__cta:hover { text-decoration: underline; }
  .modblo-cd__close {
    background: transparent; color: inherit; border: 0; cursor: pointer;
    font-size: 18px; line-height: 1; padding: 4px 8px;
    margin-left: auto;
    opacity: .6;
  }
  .modblo-cd__close:hover { opacity: 1; }
  @media (max-width: 640px) {
    .modblo-cd__inner { gap: 8px; padding: 8px 16px; font-size: 12px; }
  }
</style>

<script>
  (function () {
    var roots = document.querySelectorAll('[data-section-id="{{ section.id }}"]');
    roots.forEach(function (root) {
      if (!root.dataset.cbCd === undefined) return;
      var key = 'modblo-cd-dismissed-{{ section.id }}';
      if (root.dataset.dismissible === 'true' && localStorage.getItem(key) === '1') {
        root.hidden = true; return;
      }
      var endStr = root.dataset.end;
      if (!endStr) return;
      var end = new Date(endStr).getTime();
      if (isNaN(end)) return;
      var d = root.querySelector('[data-d]'),
          h = root.querySelector('[data-h]'),
          m = root.querySelector('[data-m]'),
          s = root.querySelector('[data-s]');
      function pad(n){ return n < 10 ? '0' + n : '' + n; }
      function tick() {
        var now = Date.now();
        var diff = Math.max(0, end - now);
        var dd = Math.floor(diff / 86400000);
        var hh = Math.floor((diff % 86400000) / 3600000);
        var mm = Math.floor((diff % 3600000) / 60000);
        var ss = Math.floor((diff % 60000) / 1000);
        d.textContent = pad(dd); h.textContent = pad(hh); m.textContent = pad(mm); s.textContent = pad(ss);
        if (diff === 0) clearInterval(int);
      }
      tick();
      var int = setInterval(tick, 1000);

      var close = root.querySelector('[data-close]');
      if (close) close.addEventListener('click', function () {
        root.hidden = true;
        try { localStorage.setItem(key, '1'); } catch(e) {}
      });
    });
  })();
</script>

{% schema %}
{
  "name": "Countdown Announcement",
  "tag": "div",
  "class": "modblo-cd-wrap",
  "settings": [
    { "type": "text", "id": "message", "label": "Message", "default": "Site-wide sale ends" },
    { "type": "text", "id": "end_date", "label": "End date (YYYY-MM-DD)", "default": "2026-12-31",
      "info": "Date in YYYY-MM-DD. Time defaults to 23:59 store-local unless overridden below." },
    { "type": "text", "id": "end_time", "label": "End time (HH:MM, 24h)", "default": "23:59" },
    { "type": "text", "id": "cta_label", "label": "CTA label", "default": "Shop now" },
    { "type": "url", "id": "cta_link", "label": "CTA link" },
    { "type": "checkbox", "id": "dismissible", "label": "Allow dismiss", "default": true },
    { "type": "color", "id": "bg", "label": "Background", "default": "#0b0b0c" },
    { "type": "color", "id": "fg", "label": "Foreground", "default": "#ffffff" },
    { "type": "color", "id": "accent", "label": "CTA color", "default": "#a78bfa" }
  ],
  "enabled_on": { "groups": ["header"] },
  "presets": [{ "name": "Countdown Announcement" }]
}
{% endschema %}

Theme editor settings

SettingTypeDefault

Message

message

text,

End date (YYYY-MM-DD)

end_date

text,

End time (HH:MM)

end_time

text,

CTA label

cta_label

text,

CTA link

cta_link

url,

Allow dismiss

dismissible

checkbox,

Background

bg

color,

Foreground

fg

color,

CTA color

accent

color,

SEO & accessibility notes

  • aria-live='polite' on the timer announces updates without interrupting screen readers.
  • Hidden state uses the [hidden] attribute, not display:none style mutations.