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 code

This is the file you'll paste into your theme.

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 %}

What you can customize

Every setting below shows up in the Shopify theme editor. Change them without touching code.

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

Link,

Allow dismiss

dismissible

Yes/No,

Background

bg

Color picker,

Foreground

fg

Color picker,

CTA color

accent

Color picker,

SEO and 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.