Skip to content

Announcement Bar Section (sections/announcement-bar.liquid)

sections/announcement-bar.liquid renders an optional announcement bar (header group) that can cycle through multiple announcements. It supports background/text colors, an optional link, and an optional emoji per announcement. Rotation is handled with Alpine.js state (x-data) and interval timers, with previous/next arrow controls when multiple announcements exist.


Dependencies & Assets

TypeFiles / Components
CSSInline {% style %} block inside the section
JSAlpine.js directives in markup (x-data, x-init, x-show, x-transition)
Blocksannouncement block type
DataRelies on section.settings and section.blocks

Notes:

  • This section assumes Alpine.js is available globally in the theme (since it uses Alpine directives).

Dynamic Styles

The section scopes colors to the section wrapper using the section’s Shopify wrapper ID:

liquid
{% style %}
  #shopify-section-{{ section.id }} {
    background-color: {{ section.settings.background_color }};
    color: {{ section.settings.text_color }};
  }
{% endstyle %}
  • The rest of the CSS for layout, arrows, and animations is defined in the same {% style %} block.

Markup Structure

The section only renders when enabled and there is at least one announcement block:

liquid
{% if section.settings.show_announcement and section.blocks.size > 0 %}
  <section class="announcement-bar-section">
    <div class="announcement-bar" x-data="...">
      <div class="page-width announcement-bar__content">
        <!-- Prev arrow (conditional) -->
        <!-- Messages -->
        <!-- Next arrow (conditional) -->
      </div>
    </div>
  </section>
{% endif %}

Prev/next controls (only when multiple blocks)

liquid
{% if section.blocks.size > 1 %}
  <button
    @click="idx = idx === 0 ? total - 1 : idx - 1"
    aria-label="Previous announcement"
    class="announcement-bar__arrow announcement-bar__arrow--prev"
    x-show="total > 1"
    type="button"
  >
    <!-- inline SVG -->
  </button>
{% endif %}

Next is symmetrical (idx = idx === total - 1 ? 0 : idx + 1).

Announcement items

Each block renders one “message” container, and Alpine toggles visibility by index:

liquid
{% for block in section.blocks %}
  <div
    {{ block.shopify_attributes }}
    x-show="idx === {{ forloop.index0 }}"
    x-transition:fade.300ms
    :class="idx === {{ forloop.index0 }} ? 'fade-in' : ''"
  >
    {{ block.settings.text }}

    {% if block.settings.link_text and block.settings.link_url %}
      <a href="{{ block.settings.link_url }}" class="announcement-bar__link" style="color: {{ text_color }};">
        {{ block.settings.link_text }}
      </a>
    {% endif %}

    {% if block.settings.emoji != blank %}
      <span class="announcement-bar__emoji">{{ block.settings.emoji }}</span>
    {% endif %}
  </div>
{% endfor %}

Notes:

  • block.settings.text is a plain text setting and is output directly.
  • Link color is set inline to match section.settings.text_color.

Behavior

Rotation logic (Alpine)

The announcement bar uses an Alpine state object with:

  • idx: current announcement index
  • total: number of announcements
  • interval: timer handle
  • startAutoScroll() / stopAutoScroll()

Auto-rotate is started via x-init="startAutoScroll()" and pauses on:

  • mouse enter / leave
  • focus in / out

Interval is based on auto_rotate_interval seconds.

Height CSS variable

The section sets a CSS variable --announcement-bar-height to the height of .announcement-bar__content. This can be used elsewhere in the theme (e.g., to offset sticky header spacing).


Schema

json
{
  "name": "Announcement Bar",
  "enabled_on": { "groups": ["header"] },
  "settings": [
    { "type": "checkbox", "id": "show_announcement", "label": "Show announcement", "default": true },
    { "type": "color", "id": "background_color", "label": "Background color", "default": "#000000" },
    { "type": "color", "id": "text_color", "label": "Text color", "default": "#FFFFFF" },
    { "type": "range", "id": "auto_rotate_interval", "label": "Auto-rotate interval (seconds)", "min": 2, "max": 15, "step": 1, "default": 4 }
  ],
  "blocks": [
    {
      "type": "announcement",
      "name": "Announcement",
      "settings": [
        { "type": "text", "id": "text", "label": "Text", "default": "Welcome to our store" },
        { "type": "text", "id": "link_text", "label": "Link text" },
        { "type": "url", "id": "link_url", "label": "Link URL" },
        { "type": "text", "id": "emoji", "label": "Emoji", "default": "🎉" }
      ]
    }
  ],
  "presets": [{ "name": "Announcement Bar" }]
}

Implementation Notes

  1. Alpine dependency: Without Alpine.js, the rotation logic and show/hide behavior won’t work.
  2. Controls: Prev/next arrows only render when there are multiple blocks.
  3. Animation: Uses CSS animation fadeInAnim and Alpine transition x-transition:fade.300ms.
  4. VitePress mustache safety: If referencing Liquid mustaches in prose/inline code, escape them like \{\{ ... \}\} to avoid blank pages. [[memory:13638067]]