Skip to main content
The Featured Collection section allows you to showcase your best products with advanced filtering, sorting, and display options. Perfect for highlighting new arrivals, best sellers, or seasonal collections.

Overview

The Featured Collection section provides:
  • Flexible Product Display with multiple grid layouts
  • Advanced Filtering by tags, vendors, and product types
  • Sorting Options by price, popularity, and date
  • Quick View Functionality for faster shopping
  • Responsive Design that looks great on all devices
  • Performance Optimized with lazy loading and efficient queries

Section Settings

Collection Selection

{% assign collection = collections[section.settings.collection] %}
{% if collection.products.size > 0 %}
  <section class="featured-collection" data-collection-id="{{ collection.id }}">
    <div class="container">
      <div class="featured-collection__header">
        {% if section.settings.title != blank %}
          <h2 class="featured-collection__title">{{ section.settings.title }}</h2>
        {% endif %}
        
        {% if section.settings.description != blank %}
          <div class="featured-collection__description">
            {{ section.settings.description }}
          </div>
        {% endif %}
      </div>
      
      <div class="featured-collection__content">
        <!-- Collection content here -->
      </div>
    </div>
  </section>
{% endif %}

Display Settings

  • Collection: Select which collection to display
  • Products to Show: Number of products (4, 8, 12, 16, 20)
  • Products per Row: Desktop layout (2, 3, 4, 5, 6)
  • Show Product Info: Title, price, vendor, rating
  • Show Quick View: Enable quick view modal
  • Show Add to Cart: Display add to cart buttons

Layout Options

  • Grid Layout: Standard product grid
  • Carousel Layout: Sliding product carousel
  • Masonry Layout: Pinterest-style layout
  • List Layout: Horizontal product list

Product Grid Implementation

Basic Product Grid

<div class="product-grid product-grid--{{ section.settings.products_per_row }}-col">
  {% for product in collection.products limit: section.settings.products_to_show %}
    <div class="product-card" data-product-id="{{ product.id }}">
      <div class="product-card__image">
        <a href="{{ product.url }}" class="product-card__link">
          <img src="{{ product.featured_image | image_url: width: 400 }}" 
               alt="{{ product.title | escape }}"
               loading="lazy"
               class="product-card__img">
        </a>
        
        {% if section.settings.show_quick_view %}
          <button class="product-card__quick-view" 
                  data-product-id="{{ product.id }}"
                  aria-label="Quick view {{ product.title }}">
            <svg width="20" height="20" viewBox="0 0 20 20" fill="currentColor">
              <path d="M10 12a2 2 0 100-4 2 2 0 000 4z"/>
              <path fill-rule="evenodd" d="M.458 10C1.732 5.943 5.522 3 10 3s8.268 2.943 9.542 7c-1.274 4.057-5.064 7-9.542 7S1.732 14.057.458 10zM14 10a4 4 0 11-8 0 4 4 0 018 0z" clip-rule="evenodd"/>
            </svg>
          </button>
        {% endif %}
      </div>
      
      <div class="product-card__content">
        {% if section.settings.show_vendor and product.vendor %}
          <p class="product-card__vendor">{{ product.vendor }}</p>
        {% endif %}
        
        <h3 class="product-card__title">
          <a href="{{ product.url }}">{{ product.title }}</a>
        </h3>
        
        <div class="product-card__price">
          {% if product.compare_at_price > product.price %}
            <span class="product-card__price-current">{{ product.price | money }}</span>
            <span class="product-card__price-compare">{{ product.compare_at_price | money }}</span>
          {% else %}
            <span class="product-card__price-current">{{ product.price | money }}</span>
          {% endif %}
        </div>
        
        {% if section.settings.show_rating and product.metafields.spr.reviews %}
          <div class="product-card__rating">
            <span class="product-card__stars">
              {% assign rating = product.metafields.spr.reviews | split: '"rating":' | last | split: ',' | first %}
              {% for i in (1..5) %}
                {% if i <= rating %}

                {% else %}

                {% endif %}
              {% endfor %}
            </span>
            <span class="product-card__review-count">
              ({{ product.metafields.spr.reviews | split: '"reviewCount":' | last | split: ',' | first }})
            </span>
          </div>
        {% endif %}
        
        {% if section.settings.show_add_to_cart and product.available %}
          <button class="product-card__add-to-cart" 
                  data-product-id="{{ product.id }}"
                  data-variant-id="{{ product.selected_or_first_available_variant.id }}">
            Add to Cart
          </button>
        {% endif %}
      </div>
    </div>
  {% endfor %}
</div>
<div class="product-carousel" data-carousel>
  <div class="product-carousel__container">
    {% for product in collection.products limit: section.settings.products_to_show %}
      <div class="product-carousel__item">
        <!-- Product card content -->
      </div>
    {% endfor %}
  </div>
  
  <button class="product-carousel__nav product-carousel__nav--prev" aria-label="Previous">
    <svg width="24" height="24" viewBox="0 0 24 24" fill="currentColor">
      <path d="M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z"/>
    </svg>
  </button>
  
  <button class="product-carousel__nav product-carousel__nav--next" aria-label="Next">
    <svg width="24" height="24" viewBox="0 0 24 24" fill="currentColor">
      <path d="M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z"/>
    </svg>
  </button>
</div>

Filtering and Sorting

Filter Implementation

{% if section.settings.show_filters %}
  <div class="collection-filters">
    <div class="collection-filters__header">
      <h3 class="collection-filters__title">Filter Products</h3>
      <button class="collection-filters__clear" data-clear-filters>
        Clear All
      </button>
    </div>
    
    <div class="collection-filters__content">
      <!-- Price Filter -->
      <div class="collection-filter">
        <h4 class="collection-filter__title">Price</h4>
        <div class="collection-filter__options">
          <label class="collection-filter__option">
            <input type="checkbox" name="price" value="0-25" data-filter>
            <span>$0 - $25</span>
          </label>
          <label class="collection-filter__option">
            <input type="checkbox" name="price" value="25-50" data-filter>
            <span>$25 - $50</span>
          </label>
          <label class="collection-filter__option">
            <input type="checkbox" name="price" value="50-100" data-filter>
            <span>$50 - $100</span>
          </label>
          <label class="collection-filter__option">
            <input type="checkbox" name="price" value="100+" data-filter>
            <span>$100+</span>
          </label>
        </div>
      </div>
      
      <!-- Vendor Filter -->
      {% if collection.all_vendors.size > 1 %}
        <div class="collection-filter">
          <h4 class="collection-filter__title">Brand</h4>
          <div class="collection-filter__options">
            {% for vendor in collection.all_vendors %}
              <label class="collection-filter__option">
                <input type="checkbox" name="vendor" value="{{ vendor | handleize }}" data-filter>
                <span>{{ vendor }}</span>
              </label>
            {% endfor %}
          </div>
        </div>
      {% endif %}
      
      <!-- Tag Filter -->
      {% if collection.all_tags.size > 0 %}
        <div class="collection-filter">
          <h4 class="collection-filter__title">Tags</h4>
          <div class="collection-filter__options">
            {% for tag in collection.all_tags %}
              <label class="collection-filter__option">
                <input type="checkbox" name="tag" value="{{ tag | handleize }}" data-filter>
                <span>{{ tag }}</span>
              </label>
            {% endfor %}
          </div>
        </div>
      {% endif %}
    </div>
  </div>
{% endif %}

Sort Implementation

{% if section.settings.show_sort %}
  <div class="collection-sort">
    <label for="sort-by" class="collection-sort__label">Sort by:</label>
    <select id="sort-by" class="collection-sort__select" data-sort>
      <option value="manual">Featured</option>
      <option value="price-ascending">Price: Low to High</option>
      <option value="price-descending">Price: High to Low</option>
      <option value="title-ascending">Name: A to Z</option>
      <option value="title-descending">Name: Z to A</option>
      <option value="created-ascending">Oldest to Newest</option>
      <option value="created-descending">Newest to Oldest</option>
      <option value="best-selling">Best Selling</option>
    </select>
  </div>
{% endif %}

CSS Styling

Product Grid CSS

.product-grid {
  display: grid;
  gap: 2rem;
  margin-bottom: 3rem;
}

.product-grid--2-col {
  grid-template-columns: repeat(2, 1fr);
}

.product-grid--3-col {
  grid-template-columns: repeat(3, 1fr);
}

.product-grid--4-col {
  grid-template-columns: repeat(4, 1fr);
}

.product-grid--5-col {
  grid-template-columns: repeat(5, 1fr);
}

.product-grid--6-col {
  grid-template-columns: repeat(6, 1fr);
}

.product-card {
  background: var(--color-surface);
  border-radius: 0.5rem;
  overflow: hidden;
  transition: transform 0.3s ease, box-shadow 0.3s ease;
}

.product-card:hover {
  transform: translateY(-4px);
  box-shadow: 0 8px 25px rgba(0, 0, 0, 0.1);
}

.product-card__image {
  position: relative;
  aspect-ratio: 1;
  overflow: hidden;
}

.product-card__img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 0.3s ease;
}

.product-card:hover .product-card__img {
  transform: scale(1.05);
}

.product-card__quick-view {
  position: absolute;
  top: 1rem;
  right: 1rem;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.9);
  border: none;
  cursor: pointer;
  opacity: 0;
  transform: translateY(10px);
  transition: all 0.3s ease;
}

.product-card:hover .product-card__quick-view {
  opacity: 1;
  transform: translateY(0);
}

.product-card__content {
  padding: 1rem;
}

.product-card__vendor {
  font-size: 0.875rem;
  color: var(--color-text-secondary);
  margin-bottom: 0.5rem;
}

.product-card__title {
  font-size: 1rem;
  font-weight: 600;
  margin-bottom: 0.5rem;
}

.product-card__title a {
  color: var(--color-text-primary);
  text-decoration: none;
}

.product-card__title a:hover {
  color: var(--color-primary);
}

.product-card__price {
  display: flex;
  gap: 0.5rem;
  align-items: center;
  margin-bottom: 0.5rem;
}

.product-card__price-current {
  font-weight: 600;
  color: var(--color-text-primary);
}

.product-card__price-compare {
  text-decoration: line-through;
  color: var(--color-text-secondary);
  font-size: 0.875rem;
}

.product-card__rating {
  display: flex;
  align-items: center;
  gap: 0.25rem;
  margin-bottom: 1rem;
}

.product-card__stars {
  color: #FFD700;
  font-size: 0.875rem;
}

.product-card__review-count {
  font-size: 0.75rem;
  color: var(--color-text-secondary);
}

.product-card__add-to-cart {
  width: 100%;
  padding: 0.75rem;
  background: var(--color-primary);
  color: white;
  border: none;
  border-radius: 0.25rem;
  cursor: pointer;
  transition: background-color 0.3s ease;
}

.product-card__add-to-cart:hover {
  background: var(--color-primary-dark);
}

Responsive Design

@media (max-width: 1024px) {
  .product-grid--5-col,
  .product-grid--6-col {
    grid-template-columns: repeat(4, 1fr);
  }
}

@media (max-width: 768px) {
  .product-grid--3-col,
  .product-grid--4-col,
  .product-grid--5-col,
  .product-grid--6-col {
    grid-template-columns: repeat(2, 1fr);
  }
  
  .product-grid--2-col {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 480px) {
  .product-grid {
    grid-template-columns: 1fr;
    gap: 1rem;
  }
}

JavaScript Functionality

Quick View Implementation

// Quick view functionality
document.addEventListener('click', function(e) {
  if (e.target.matches('.product-card__quick-view')) {
    const productId = e.target.dataset.productId;
    openQuickView(productId);
  }
});

function openQuickView(productId) {
  // Fetch product data
  fetch(`/products/${productId}.js`)
    .then(response => response.json())
    .then(product => {
      // Create and show quick view modal
      const modal = createQuickViewModal(product);
      document.body.appendChild(modal);
      
      // Show modal
      setTimeout(() => {
        modal.classList.add('quick-view--visible');
      }, 10);
    })
    .catch(error => {
      console.error('Error loading product:', error);
    });
}

function createQuickViewModal(product) {
  const modal = document.createElement('div');
  modal.className = 'quick-view';
  modal.innerHTML = `
    <div class="quick-view__overlay"></div>
    <div class="quick-view__content">
      <button class="quick-view__close" aria-label="Close">×</button>
      <div class="quick-view__product">
        <div class="quick-view__image">
          <img src="${product.featured_image}" alt="${product.title}">
        </div>
        <div class="quick-view__info">
          <h2 class="quick-view__title">${product.title}</h2>
          <div class="quick-view__price">${product.price}</div>
          <div class="quick-view__description">${product.description}</div>
          <button class="quick-view__add-to-cart" data-product-id="${product.id}">
            Add to Cart
          </button>
        </div>
      </div>
    </div>
  `;
  
  // Close modal functionality
  modal.addEventListener('click', function(e) {
    if (e.target.matches('.quick-view__overlay, .quick-view__close')) {
      closeQuickView(modal);
    }
  });
  
  return modal;
}

function closeQuickView(modal) {
  modal.classList.remove('quick-view--visible');
  setTimeout(() => {
    modal.remove();
  }, 300);
}

Filter and Sort Implementation

// Filter functionality
document.addEventListener('change', function(e) {
  if (e.target.matches('[data-filter]')) {
    applyFilters();
  }
  
  if (e.target.matches('[data-sort]')) {
    applySort(e.target.value);
  }
});

function applyFilters() {
  const filters = {};
  
  // Collect all active filters
  document.querySelectorAll('[data-filter]:checked').forEach(checkbox => {
    const name = checkbox.name;
    const value = checkbox.value;
    
    if (!filters[name]) {
      filters[name] = [];
    }
    filters[name].push(value);
  });
  
  // Apply filters to products
  const products = document.querySelectorAll('.product-card');
  
  products.forEach(product => {
    let shouldShow = true;
    
    // Check each filter type
    Object.keys(filters).forEach(filterType => {
      const filterValues = filters[filterType];
      const productValue = product.dataset[filterType];
      
      if (filterValues.length > 0 && !filterValues.includes(productValue)) {
        shouldShow = false;
      }
    });
    
    // Show/hide product
    product.style.display = shouldShow ? 'block' : 'none';
  });
}

function applySort(sortBy) {
  const productGrid = document.querySelector('.product-grid');
  const products = Array.from(productGrid.children);
  
  products.sort((a, b) => {
    const aValue = getProductValue(a, sortBy);
    const bValue = getProductValue(b, sortBy);
    
    if (sortBy.includes('ascending')) {
      return aValue > bValue ? 1 : -1;
    } else {
      return aValue < bValue ? 1 : -1;
    }
  });
  
  // Reorder products in DOM
  products.forEach(product => {
    productGrid.appendChild(product);
  });
}

function getProductValue(product, sortBy) {
  switch (sortBy) {
    case 'price-ascending':
    case 'price-descending':
      return parseFloat(product.dataset.price);
    case 'title-ascending':
    case 'title-descending':
      return product.dataset.title;
    case 'created-ascending':
    case 'created-descending':
      return new Date(product.dataset.created);
    default:
      return 0;
  }
}

Best Practices

Performance Optimization

  1. Lazy Loading: Use lazy loading for product images
  2. Pagination: Implement pagination for large collections
  3. Caching: Cache collection data when possible
  4. Optimized Queries: Use efficient Liquid queries

User Experience

  1. Clear Filtering: Make filters easy to understand and use
  2. Visual Feedback: Provide clear feedback for user actions
  3. Mobile Optimization: Ensure great mobile experience
  4. Accessibility: Follow WCAG guidelines

SEO Optimization

  1. Structured Data: Add product schema markup
  2. Meta Tags: Optimize meta titles and descriptions
  3. URL Structure: Use clean, descriptive URLs
  4. Image Alt Text: Provide descriptive alt text

Troubleshooting

Common Issues

  1. Products Not Loading: Check collection settings and product availability
  2. Filters Not Working: Verify JavaScript implementation and data attributes
  3. Layout Breaking: Check responsive CSS and grid settings
  4. Performance Issues: Optimize images and reduce JavaScript complexity

Performance Issues

  1. Slow Loading: Implement lazy loading and optimize images
  2. Large Collections: Use pagination or limit product count
  3. Complex Filters: Optimize filter logic and reduce DOM queries