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
    • 6. FAQ
    • 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
      • Quote
      • Register
      • RelatedProducts
      • SingleBlog
      • Stores
      • TextWithImage
      • ThankYouPage
      • TopBar
      • Wishlist
    • 3. Reusables
      • _Overview
      • Addresses
      • AddressForm
      • AnnouncementModal
      • BackToTop
      • BillingRetail
      • Company
      • General
      • Login
      • LoginModal
      • MonthlyTransactions
      • Orders
      • Payment
      • ProductAttachments
      • ProductAttributes
      • ProductComparisonButton
      • ProductComparisonFloatingButton
      • ProductGridItem
      • ProductListItem
      • ProductModal
      • ProfileInfo
      • PromptModal
      • Quotes
      • Register
      • Services
      • Shipping
      • ShoppingLists
      • ShoppingListsButton
      • ShoppingListsNavbar
      • Toast
      • Transactions
      • Users
      • VariantContent
      • WishlistButton
    • 4. Assets
      • Fonts
      • Images
      • Templates
      • Javascript
        • _Overview
        • theme.js
      • Css - Scss
        • _Overview
        • ThemeClasses
    • 5. SDK
      • _Overview
      • LiquidGlobals
      • ServicesSDK
  1. 2. Components

BlogList

Purpose#

The BlogList component renders a blog listing page section with:
A title (“Stay informed”)
Optional category description and category/general header image
A category navigation list (including an “All” entry)
A grid of blog post cards
Pagination (with a sliding window UI and accessible labels)
Source template: Components/BlogList/Default.liquid.

Inputs (model contract)#

Model shape (storefront example)#

{
  "totalPages": 1,
  "page": 1,
  "categories": [
    {
      "id": "Category Id",
      "title": "Sample category title",
      "alias": "sample-category-alias"
    },
    ...
  ],
  "generalImage": null,
  "blogList": [
    {
      "title": "Sample blog title",
      "content": "<p>Sample content</p>",
      "summaryHtml": "<p>Sample summary</p>",
      "alias": "sample-blog-alias",
      "publishedAt": "2025-01-01T00:00:00+00:00",
      "mediaItem": {
        "id": "Image Id",
        "link": "https://example.com/sample",
        "mediaType": "Image"
      }
    },
    ...
  ],
  "name": "BlogList",
  "view": "Default",
  "section": "SectionA",
  "settings": {
    "id": "Component Id",
    "section": "SectionA",
    "type": "NoirBlogList",
    "name": "BlogList",
    "configuredInContentApi": true,
    "view": "Default",
    "displayName": "",
    "cssClass": ""
  },
  "translations": {
    "stayInformed": "Sample translation",
    "previousPage": "Sample translation",
    "nextPage": "Sample translation",
    "...": "..."
  }
}

Required fields#

settings.id
Used for the wrapper id: comp-{{ id }}
pagination.pageNumber (number)
Current page.
pagination.numberOfPages (number)
Total pages used to build pagination UI.

Optional fields#

settings.cssClass
Applied to the wrapper only when non-empty and not (UNDEFINED).
The template also reads data from Root.Page.Data (page-level view model).
categories[]
If present, renders the category navigation links.
generalImage (object or null)
Fallback image when the current category doesn’t provide an image.
blogList[]
The list of blog items to render. If empty, a “not found” message is shown.

JavaScript#

Global object#

The component exposes a global object:
It’s used from the template in two places:
Per-card reading time:
x-data='bloglistdefault.singlePost({{ blog.content | serialize }})'
Pagination navigation:
@click="bloglistdefault.redirectToState(pageNumber)"

singlePost#

Returns an Alpine component object that computes and stores reading time for a single blog post.
It exposes:
time: { hours: -1, minutes: -1 }
init()
getReadingTime()
Returned state conventions:
time.hours = -1 means “don’t show hours”.
time.minutes:
-1 → not computed
-2 → “< 1 minute”
>= 1 → minutes

init#

Runs on Alpine mount and calls this.getReadingTime().

getReadingTime#

Computes reading time from content using an assumed speed of 3.8 words/sec and stores it in this.time.
Rules:
If hours > 0, sets this.time.hours.
If minutes === 0 and seconds > 0, sets this.time.minutes = -2.
If minutes > 0, sets this.time.minutes (rounded up when seconds remain).

redirectToState#

Client-side navigation helper used by pagination.
Case-by-case behavior:
1.
If newPage is a string
Treats it as a full URL and redirects to it:
window.location.href = newPage
This supports cases where pagination buttons already have a full URL precomputed.
2.
If newPage is a number
Creates a fresh querystring containing only page:
const params = new URLSearchParams();
params.set("page", Number(newPage));
Redirects to:
${window.location.pathname}?page=<n>
3.
If newPage is null/undefined
Reloads the current URL (same path + existing querystring):
window.location.href = window.location.pathname + window.location.search

Dependencies#

Alpine.js (for x-data, x-show, reactive time fields)
Theme styles for pagination, grid, and typography

Notes#

blog.content is used for reading time calculation. If it contains HTML, the word count will include markup tokens as words, which can slightly affect the reading time estimate.
Pagination UI is generated server-side (Liquid) but navigation is performed client-side by building a ?page= URL.
Category selection depends on Root.Page.Data.BlogCategory; if the page data doesn’t set it consistently, the active link highlighting/description/image may not behave as expected.

Extras#

Template behavior (Liquid + Alpine)#

Title and category description#

Title uses translations.stayInformed
The template assigns currentCategory = Root.Page.Data.BlogCategory.
If currentCategory.description exists, it is rendered under the title.

Category/general header image#

The component can render a header image (different layout for mobile vs desktop).
It chooses the image source in this order:
1.
Current category image (if currentCategory.mediaItem.link exists)
2.
Otherwise generalImage.link (if provided)
Alt text falls back to translations.noImageAltAvailable when needed.

Categories navigation#

Always renders an “All” link to /blog/posts
Renders each category link to /blog/posts/<alias>
The active category link becomes disabled via pointer-events-none + secondary text class.

Blog cards grid#

Renders a grid of links to /blog/post/<blog.alias>
If the blog has mediaItem.link, it shows an image.
Summary/description behavior:
If summaryHtml exists, it renders that.
Else, it renders content.
Uses line clamping; clamping differs depending on whether an image exists.

Reading time indicator (per blog card)#

Each blog card initializes an Alpine scope to compute reading time:
x-data='singlePost({{ blog.content | serialize }})'
Then prints:
hours (if > 0)
minutes (if > 0)
< 1 minute when minutes are effectively below 1
Modified at 2026-05-11 14:45:54
Previous
BlogCategoryList
Next
BrandList
Built with