Home
Wiki
Home
Wiki
  1. 2. Components
  • Back to home
  • 1. Themes
  • Vs Code
    • Getting Started
  • Kitchenware
    • Layout
      • New Layout
      • Legacy Layout
    • Components
      • Announcement
      • Banner Carousel
      • Banner With Products Carousel
      • Blog Category List
      • Blog List
      • Brand List
      • Brands Carousel
      • Breadcrumb
      • Call To Action
      • Cart
      • Categories List
      • Change Password
      • Checkout
      • Cookie Manager
      • Filter list
      • Footer
      • Forgot Password
      • Form
      • Hero Carousel
      • Icon Block
      • Invitation
      • Last Visited Products
      • Layout
      • Login
      • Map
      • Nav Bar
      • Offer
      • Product Attachments
      • Product Attributes
      • Product Documentation
      • Product Expected
      • Product Modal
      • Products Block
      • Products Carousel
      • Product Single
      • Profile
      • Quote
      • Register
      • Related Products
      • Search
      • Stores
      • Subscribe Newsletter
      • Text with Image
      • Top Bar
      • Video
    • Reusables
      • Getting Started
    • Assets
      • Getting Started
    • SDK
      • Products
        • _findProductsByCategory
        • _findProductsByIds
        • _findProductsByTitle
        • _findProductsByFilter
        • _findProductsByCriteria
        • _findProductsAndCalculate
        • _findProductsThenCalculate
        • _getProductAttributeSet
        • _setLastVisited
      • Categories
        • _findCategoryTreeById
        • _findCategoriesByIds
        • _findCategoryByAlias
        • _findCategoryTreeByAlias
        • _getCategoryContent
      • Collections
        • _getCollectionContent
        • _findCollectionsByIds
        • _findCollectionsByIdsThenCalculate
      • Brands
        • _getBrandContent
        • _findBrandsByIds
      • Cart
        • _addToCartMulti
        • _addToCart
        • _setCart
        • _clearCart
        • _setCartListener
        • _removeFromCart
        • _calculateCart
      • Checkout
        • _startCheckout
        • _updateCheckout
        • _completeCheckout
      • Shopping Lists
        • _getShoppingLists
        • _updateShoppingList
        • _createShoppingList
        • _deleteShoppingList
        • _getShoppingListByAlias
      • Navigation
        • _getFooterMenu
        • _getHeaderMenu
      • Users
        • _getUserById
      • Utils
        • _calculateCurrency
        • _getCurrencySymbol
        • _getCulture
        • _subscribeToNewsletter
        • _findUnitsByIds
  • Noir
    • 0. Introduction
    • 1. Structure
      • Overview
      • LayoutA.liquid
      • ComponentsList.liquid
      • Metas.liquid
      • CssVariables.liquid
      • Json.liquid
      • GoogleTagManager.liquid
      • StagingButton.liquid
    • 2. Components
      • Overview
      • Announcement
      • BannerCarousel
      • BlogCategoryList
      • BlogList
      • BrandList
      • Breadcrumb
      • Cart
      • CategoriesList
      • ChangePassword
      • Checkout
      • CookieManager
      • FilterList
      • Footer
      • ForgotPassword
      • Form
      • IconBlock
      • Invitation
      • LastVisitedProducts
      • Login
      • Map
      • NavBar
      • ProductAttachments
      • ProductAttributes
      • ProductComparison
      • ProductDocumentation
      • ProductMixList
      • ProductsBlock
      • ProductsCarousel
      • ProductSingle
      • Profile
      • Register
      • RelatedProducts
      • SingleBlog
      • Stores
      • TextWithImage
      • ThankYouPage
      • TopBar
      • Wishlist
    • 3. Reusables
      • Overview
      • Addresses
      • BillingRetail
      • AddressForm
      • AnnouncementModal
      • BackToTop
      • Company
      • General
      • Login
      • LoginModal
      • Orders
      • Payment
      • ProductAttachments
      • ProductAttributes
      • ProductComparisonButton
      • ProductComparisonFloatingButton
      • ProductGridItem
      • ProductListItem
      • ShoppingListsButton
      • ProductModal
      • ProfileInfo
      • PromptModal
      • Register
      • Shipping
      • ShoppingLists
      • ShoppingListsNavbar
      • Toast
      • Users
      • VariantContent
      • WishlistButton
      • Services
    • 4. Assets
      • Fonts
      • Images
      • Templates
      • Javascript
        • Overview
        • theme.js
      • Css / Scss
        • Overview
        • ThemeClasses
    • 5. SDK
      • Overview
      • LiquidGlobals
      • ServicesSDK
  1. 2. Components

Announcement

Purpose#

The Announcement component displays a slide-in notifications panel (drawer) that lists announcements/notifications.
Open/close is controlled via the Alpine store: $store.announcements
Clicking an item closes the drawer and opens the announcement modal via: $store.announcementModal
Unread state/mark-as-viewed is handled via: Alpine.store('viewedAnnouncements')

Inputs (model contract)#

Model shape (storefront example)#

{
  "announcements": [
    {
      "id": "Announcement Id",
      "title": "Sample title",
      "description": "<p>Sample description</p>\n",
      "buttonPrimaryText": "Sample button text",
      "buttonPrimaryLink": "/sample",
      "isRead": false,
      "image": {
        "id": "Image Id",
        "galleryId": "Gallery Id",
        "link": "https://example.com/sample",
        "mediaType": "Image"
      }
    }
  ],
  "name": "Announcement",
  "view": "Default",
  "section": "SectionHeader",
  "settings": {
    "id": "Component Id",
    "section": "SectionHeader",
    "type": "NoirAnnouncement",
    "name": "Announcement",
    "configuredInContentApi": true,
    "view": "Default",
    "displayName": "",
    "cssClass": "",
    "header": "",
    "alignment": "Left"
  },
  "translations": {
    "closeAnnouncementsModalMessage": "Sample translation",
    "notifications": "Sample translation",
    "noNotificationsFound": "Sample translation",
    "...": "..."
  }
}

Required fields#

settings.id
Used to form the wrapper DOM id: comp-{{ id }}

Optional fields#

settings.cssClass
Appended to the wrapper only when non-empty and not (UNDEFINED).
announcements[]
List of announcements. If empty, the component shows the “no notifications” state.

Announcement item fields#

Each item is expected to include:
id (string)
title (string)
description (string, optional HTML)
isRead (boolean)
Useful for authenticated users: the modal filters to show only !isRead announcements, and read state can be persisted server-side via setReadAnnouncementIds(...).
Note
For authenticated users, isRead is the server-provided read flag.
For guest users, read/unread is tracked client-side via the viewedAnnouncements store.

JavaScript#

Global object#

The component exposes a global object:
and it’s used from Liquid via Alpine like:
x-data="announcementdefault.initComponent(announcements)"
initComponent(...) returns the Alpine component state + methods.

initComponent(announcements)#

What it does
Factory function that receives announcements (Liquid-serialized data) and returns an Alpine object containing:
announcements: the list rendered by the template
height: a dynamic drawer height so it fits under the header
lifecycle method init()
helpers (isAnnouncementViewed, calculateHeight)
Advice
Keep the signature initComponent(announcements) stable, since it’s a contract with the Liquid template.
If you ever need more inputs, add them in a backward-compatible way (e.g., optional second argument), because multiple components follow the same factory pattern.

init()#

What it does
Automatically runs when Alpine mounts the component.
Calls calculateHeight() immediately to initialize the drawer height.
Registers window event listeners:
resize → recalculates height
scroll → recalculates height
Why it exists
In sticky headers / top bars layouts, available viewport height (or header height) may change on scroll/resize.
The drawer must keep a correct max height under the header.
Advice
There’s no cleanup (listeners aren’t removed). This is usually fine if the component isn’t mounted/unmounted repeatedly.
If you introduce partial navigation / re-mounting without a full refresh, you may end up with duplicated listeners. In that case:
add a guard flag (e.g., listenersBound), or
throttle/debounce calls to calculateHeight() for performance.

isAnnouncementViewed(id)#

What it does
Returns whether the announcement id is already marked as viewed in the client store:
Alpine.store("viewedAnnouncements").isViewed(id)
The template uses this to drive unread styling / badge visibility.
Advice
Don’t store “viewed/read” state locally in the component; the store is intentionally global so other UI pieces (like header counters) stay in sync.
For authenticated users, “read/unread” may also come from server state (isRead) and can differ from the client store. Keep the responsibilities clear:
Drawer: mainly client “viewed” store
Modal: may persist server-side read state

calculateHeight()#

What it does
Finds the <header> element:
document.querySelector("header")
Reads its height:
header.offsetHeight (or 0 if not found)
Computes available drawer height:
window.innerHeight - headerHeight
Stores it as a px string:
this.height = "...px"
Advice
If the layout changes and the header is no longer a <header> element, the computed height becomes full viewport height. If that happens:
update the selector to something more stable (e.g., header.site-header), or
pass/retrieve a reference via x-ref from the layout.
If scroll performance becomes an issue, throttle the scroll handler (e.g., one calculation per animation frame).
offsetHeight includes borders (not margins), which is typically what you want for “fit under fixed header” behavior.

Global Alpine stores (used by Announcement)#

The Announcement component is store-driven. It doesn’t “own” the open/close state by itself — it reacts to, and triggers, actions on global Alpine stores.

$store.announcements (drawer state)#

This store controls the Notifications drawer visibility.
The component uses it as:
Visibility flag:
x-show="$store.announcements.visible"
Close actions:
@click.outside="$store.announcements.close()"
Close button: @click="$store.announcements.close()"
What it means in practice
When something elsewhere in the theme calls $store.announcements.open() (or sets visible = true), the drawer becomes visible.
When the user clicks outside or presses the close button, close() is called and the drawer hides.
Note
The store is responsible for the “global UI state” (open/close), so the drawer can be triggered from anywhere (e.g. header icon).

$store.announcementModal (modal state)#

This store controls the AnnouncementModal (the modal that shows a full announcement).
The drawer triggers it when a user clicks a list item:
$store.announcementModal.open(announcement.id)
What it means in practice
The drawer lists announcements (summary).
The modal shows details for the selected announcement id (detail view).
The selected id is passed through the store, allowing the modal reusable to react and display the correct content.

Alpine.store('viewedAnnouncements') (client “viewed/unviewed” tracking)#

This store keeps track of which announcement ids have been “viewed” by the user on the client.
Used in the drawer to:
Decide unread styling:
!isAnnouncementViewed(announcement.id)
Mark an item as viewed on click:
Alpine.store('viewedAnnouncements').addViewedId(announcement.id)
Guest vs authenticated behavior
Guest users: viewedAnnouncements is the main mechanism used to track unread/read on the client (usually via local storage).
Authenticated users: read state is also reflected server-side via the isRead flag and can be persisted with API calls (done by the modal logic).

Interactions summary#

When an announcement row is clicked, the component performs a coordinated sequence via stores:
1.
Marks as viewed (client):
viewedAnnouncements.addViewedId(id)
2.
Updates any counters/listeners:
$dispatch('update-remaining')
3.
Closes the drawer:
$store.announcements.close()
4.
Opens the detail modal for the selected id:
$store.announcementModal.open(id)

Dependencies#

Alpine.js
Alpine stores:
$store.announcements
$store.announcementModal
Alpine.store('viewedAnnouncements')

Notes#

description is rendered using x-html, so it is treated as trusted HTML (ensure server sanitization where applicable).
If $store.announcements or $store.announcementModal are missing, the drawer/modal flow won’t work.

Extras#

Template behavior (Liquid + Alpine)#

Visibility & transitions#

Drawer visibility is controlled by: x-show="$store.announcements.visible"
Uses Alpine transitions:
fade for the overlay
slide-in/out for the drawer panel
Closes when:
clicking outside (@click.outside)
clicking the close button

Rendering announcements#

If announcements.length > 0, it renders a list of clickable rows.
If announcements.length == 0, it renders a “No notifications found” message.

Unread indicator#

Unread state is calculated via:
isAnnouncementViewed(announcement.id)
Unread items get:
zebra background
a small dot badge (with screen-reader text)

Click behavior#

Clicking an announcement row:
marks it as viewed: Alpine.store('viewedAnnouncements').addViewedId(...)
dispatches: update-remaining
closes drawer: $store.announcements.close()
opens modal: $store.announcementModal.open(announcement.id)
Modified at 2026-04-14 13:18:56
Previous
Overview
Next
BannerCarousel
Built with