Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/Shopify/horizon/llms.txt

Use this file to discover all available pages before exploring further.

Horizon collection pages feature advanced filtering, infinite scroll, customizable product grids, and responsive layouts optimized for browsing products.

Key Features

  • Infinite Scroll: Automatically load more products as users scroll
  • Filtering System: Advanced product filtering by tags, variants, price, and more
  • Grid & Editorial Layouts: Choose between classic grid or editorial organic layout
  • Responsive Cards: Adjustable card sizes for mobile and desktop
  • Performance Optimized: Uses view transitions and efficient rendering

Collection Container

The main collection section wraps the product grid and filters:
<results-list
  class="section product-grid-container color-{{ section.settings.color_scheme }}"
  section-id="{{ section.id }}"
  infinite-scroll="{{ section.settings.enable_infinite_scroll }}"
>
  <div class="collection-wrapper grid gap-style">
    {% content_for 'block', type: 'filters', id: 'filters' %}
    
    {% paginate collection.products by products_per_page %}
      {% render 'product-grid',
        section: section,
        children: children,
        products: collection.products,
        paginate: paginate
      %}
    {% endpaginate %}
  </div>
</results-list>

Layout Types

Grid Layout

Classic grid with consistent card sizing:
layout_type: grid

product_card_size:
  options:
    - small
    - medium (default)
    - large
    - extra-large

Editorial Layout

Organic layout with varying card sizes:
layout_type: organic
Features:
  • Variable card sizes for visual interest
  • Masonry-style layout
  • Better for editorial/lifestyle brands

Product Grid Rendering

Paginated Products

{% assign products_per_page = 24 %}
{% if section.settings.enable_infinite_scroll == false %}
  {% assign products_per_page = section.settings.products_per_page %}
{% endif %}

{% paginate collection.products by products_per_page %}
  {% capture children %}
    {% for product in collection.products %}
      <li id="{{ section.id }}-{{ product.id }}"
          class="product-grid__item product-grid__item--{{ forloop.index0 }}"
          data-page="{{ paginate.current_page }}"
          data-product-id="{{ product.id }}"
          ref="cards[]">
        
        {% content_for 'block',
          type: '_product-card',
          id: 'product-card',
          closest.product: product
        %}
      </li>
    {% endfor %}
  {% endcapture %}
  
  {% render 'product-grid',
    section: section,
    children: children,
    products: collection.products,
    paginate: paginate,
    enable_infinite_scroll: section.settings.enable_infinite_scroll
  %}
{% endpaginate %}

Product Card Attributes

id="{{ section.id }}-{{ product.id }}"
Unique identifier for each product card, used for scroll anchoring.

Infinite Scroll

Automatic product loading as users scroll:

Configuration

enable_infinite_scroll:
  type: checkbox
  default: true
When enabled:
  • Products load automatically when scrolling near bottom
  • Uses Intersection Observer API
  • Shows loading indicator
  • Updates URL with current page
When disabled:
  • Shows pagination controls
  • Manual page navigation
  • Configurable products per page

Products Per Page

products_per_page:
  min: 8
  max: 36
  step: 4
  default: 24
  visible_if: enable_infinite_scroll == false
When infinite scroll is enabled, products per page is fixed at 24 for optimal performance.

Card Sizes

Desktop Card Size

product_card_size:
  options:
    - small    # ~250px width
    - medium   # ~350px width (default)
    - large    # ~450px width
    - extra-large # ~600px width
  default: medium
  visible_if: layout_type == 'grid'

Mobile Card Size

mobile_product_card_size:
  options:
    - small  # 2 columns (default)
    - large  # 1 column
  default: small
CSS Implementation:
@media screen and (max-width: 749px) {
  .product-grid[data-mobile-size='small'] {
    grid-template-columns: repeat(2, 1fr);
  }
  
  .product-grid[data-mobile-size='large'] {
    grid-template-columns: 1fr;
  }
}

Grid Layout Settings

Width Options

product_grid_width:
  options:
    - centered (Page width, default)
    - full-width
  default: centered

Full Width on Mobile

full_width_on_mobile:
  type: checkbox
  default: true
  visible_if: product_grid_width != 'full-width'
Forces full-width grid on mobile even when using page-width on desktop.

Gap Settings

columns_gap_horizontal:
  min: 0
  max: 50
  step: 1
  unit: px
  default: 16
Space between product cards horizontally.
CSS Variables:
.product-grid {
  gap: var(--columns-gap-vertical) var(--columns-gap-horizontal);
}

Padding Settings

padding-inline-start:
  min: 0
  max: 100
  step: 1
  unit: px
  default: 0

Filtering System

Integrated filtering block for product discovery:
{% content_for 'block',
  type: 'filters',
  id: 'filters',
  results: collection,
  results_size: collection.products_count
%}
Filter Types:
  • Tags
  • Variants (color, size, etc.)
  • Price range
  • Availability
  • Vendor
  • Product type

URL Hash Navigation

Automatic scroll to products when using URL hash:
const url = new URL(window.location.href);
if (url.hash) {
  document.addEventListener('DOMContentLoaded', () => {
    const card = document.getElementById(url.hash.slice(1));
    if (card) {
      card.scrollIntoView({ behavior: 'instant' });
    }
  }, { once: true });
}
Usage:
/collections/all#product-123
Scrolls directly to product with ID 123.

View Transitions

Smooth animations when emptying cart:
html:active-view-transition-type(empty-cart-page) {
  .cart-items-component {
    view-transition-name: cart-page-content;
  }
}

::view-transition-old(cart-page-content) {
  animation: cart-page-content-old var(--animation-speed-fast) forwards;
}

Grid Column System

The collection wrapper uses a smart grid:
.collection-wrapper {
  display: grid;
  grid-template-columns: var(--grid-column--mobile);
}

@media screen and (min-width: 750px) {
  .collection-wrapper {
    grid-template-columns: var(--grid-column--desktop);
  }
}
With Filters:
--grid-column--mobile: 1fr;
--grid-column--desktop: 250px 1fr; /* Filters | Products */
Without Filters:
--grid-column--mobile: 1fr;
--grid-column--desktop: 1fr;

JavaScript Module

The collection list is powered by results-list.js:
<script src="{{ 'results-list.js' | asset_url }}" type="module" fetchpriority="low"></script>
Handles:
  • Infinite scroll detection
  • URL parameter management
  • Filter state
  • Page transitions
  • Analytics events

Performance Optimizations

Lazy Loading

{{ product.featured_image | image_tag: loading: 'lazy' }}
All product images are lazy-loaded by default.

Fetchpriority

<script src="{{ 'results-list.js' | asset_url }}" fetchpriority="low"></script>
Non-critical JavaScript loads with low priority.

Content Visibility

.product-card {
  content-visibility: auto;
  contain-intrinsic-size: 300px 400px;
}

Accessibility

<results-list role="region" aria-label="{{ 'accessibility.product_list' | t }}">
  <div role="list">
    <div role="listitem">...</div>
  </div>
</results-list>
When loading new products via infinite scroll, focus is managed to prevent disorientation.

Schema Configuration

{
  "name": "Collection Container",
  "enabled_on": {
    "templates": ["collection"]
  },
  "settings": [
    {
      "type": "select",
      "id": "layout_type",
      "options": [
        { "value": "grid", "label": "Grid" },
        { "value": "organic", "label": "Editorial" }
      ],
      "default": "grid"
    },
    {
      "type": "select",
      "id": "product_card_size",
      "options": [
        { "value": "small", "label": "Small" },
        { "value": "medium", "label": "Medium" },
        { "value": "large", "label": "Large" },
        { "value": "extra-large", "label": "Extra Large" }
      ],
      "default": "medium",
      "visible_if": "{{ section.settings.layout_type == 'grid' }}"
    },
    {
      "type": "select",
      "id": "mobile_product_card_size",
      "options": [
        { "value": "small", "label": "Small" },
        { "value": "large", "label": "Large" }
      ],
      "default": "small"
    },
    {
      "type": "checkbox",
      "id": "enable_infinite_scroll",
      "label": "Auto-load products",
      "default": true
    },
    {
      "type": "range",
      "id": "products_per_page",
      "label": "Products per page",
      "min": 8,
      "max": 36,
      "step": 4,
      "default": 24,
      "visible_if": "{{ section.settings.enable_infinite_scroll == false }}"
    },
    {
      "type": "select",
      "id": "product_grid_width",
      "options": [
        { "value": "centered", "label": "Page" },
        { "value": "full-width", "label": "Full" }
      ],
      "default": "centered"
    },
    {
      "type": "checkbox",
      "id": "full_width_on_mobile",
      "label": "Full width on mobile",
      "default": true
    },
    {
      "type": "range",
      "id": "columns_gap_horizontal",
      "label": "Horizontal gap",
      "min": 0,
      "max": 50,
      "step": 1,
      "unit": "px",
      "default": 16
    },
    {
      "type": "range",
      "id": "columns_gap_vertical",
      "label": "Vertical gap",
      "min": 0,
      "max": 50,
      "step": 1,
      "unit": "px",
      "default": 16
    },
    {
      "type": "color_scheme",
      "id": "color_scheme",
      "default": "scheme-1"
    }
  ]
}