Skip to content

Sidebar Template

The sidebar template displays filters in a persistent sidebar next to the product grid, ideal for desktop experiences with extensive filtering options.

Implementation

Create a new snippet (typically named rebuy-smart-collection-template) and paste the template code. Then render the snippet in your collection template:

{% render 'rebuy-smart-collection-template' %}

Add this at the bottom of collection.liquid or the main file that renders on collection pages.

Template Detection

When Rebuy loads, it searches for a custom template in the theme code. If found, it uses the custom template instead of the standard template.

Template

The template wraps content with {% raw %} and {% endraw %} so Vue.js double curly brace syntax doesn't get parsed as Liquid.

Last Updated: January 21, 2026
{% raw %}
<script id="rebuy-smart-collection-sidebar-template" type="text/template">
  <div v-if="shouldShowCollectionsPage()" id="rebuy-smart-collection-sidebar" class="rebuy-smart-collections">
    <div class="rebuy-smart-collections__page">

      <!-- Hero Section -->
      <div class="rebuy-smart-collections__hero" v-bind:class="{ 'rebuy-smart-collections__hero-no-image': !shouldShowHeroImage() }">
        <div class="rebuy-smart-collections__hero-text">
          <h1 class="rebuy-smart-collections__hero-title">{{settings.collectionData?.name || ''}}</h1>
          <div v-if="shouldShowHeroDescription()" class="rebuy-smart-collections__hero-description" v-html="settings.collectionData?.description || ''"></div>
        </div>
        <div v-if="shouldShowHeroImage()" class="rebuy-smart-collections__hero-image">
          <img v-bind:src="getCollectionHeroImage()" />
        </div>
      </div>

      <!-- Main Layout -->
      <div class="rebuy-smart-collections__layout">

        <!-- Sidebar Filters -->
        <aside class="rebuy-smart-collections__sidebar">
          <div class="rebuy-smart-collections__sidebar-header">
            <h3>Filters</h3>
            <button v-if="hasSelectedFilters()" @click="resetFilters()" class="rebuy-smart-collections__reset-link">
              Reset All
            </button>
          </div>

          <!-- Price Range -->
          <div v-if="shouldShowPriceFilter()" class="rebuy-smart-collections__filter-section">
            <h4 class="rebuy-smart-collections__filter-title">Price</h4>
            <div class="rebuy-smart-collections__price-inputs">
              <div class="rebuy-smart-collections__price-field">
                <label for="price-min" class="sr-only">Minimum price</label>
                <span class="rebuy-smart-collections__currency" v-html="shopCurrencySymbol()"></span>
                <input type="number" id="price-min" v-model="filterPrice.min" placeholder="Min" />
              </div>
              <span class="rebuy-smart-collections__price-separator">-</span>
              <div class="rebuy-smart-collections__price-field">
                <label for="price-max" class="sr-only">Maximum price</label>
                <span class="rebuy-smart-collections__currency" v-html="shopCurrencySymbol()"></span>
                <input type="number" id="price-max" v-model="filterPrice.max" placeholder="Max" />
              </div>
              <button @click="applyPriceFilter()" class="rebuy-smart-collections__price-apply">Apply</button>
            </div>
          </div>

          <!-- Availability -->
          <div v-if="shouldShowAvailabilityFilter()" class="rebuy-smart-collections__filter-section">
            <h4 class="rebuy-smart-collections__filter-title">Availability</h4>
            <div class="rebuy-smart-collections__filter-options">
              <label class="rebuy-smart-collections__filter-option">
                <input type="radio" v-model="filterAvailability" value="all" @change="applyFilters()" />
                <span>All</span>
              </label>
              <label class="rebuy-smart-collections__filter-option">
                <input type="radio" v-model="filterAvailability" value="in-stock" @change="applyFilters()" />
                <span>In Stock</span>
              </label>
              <label class="rebuy-smart-collections__filter-option">
                <input type="radio" v-model="filterAvailability" value="sold-out" @change="applyFilters()" />
                <span>Sold Out</span>
              </label>
            </div>
          </div>

          <!-- Tags -->
          <div v-if="aggregatedFilters.tags && aggregatedFilters.tags.length > 0" class="rebuy-smart-collections__filter-section">
            <h4 class="rebuy-smart-collections__filter-title">Tags</h4>
            <div class="rebuy-smart-collections__filter-options">
              <label v-for="tag in aggregatedFilters.tags" class="rebuy-smart-collections__filter-option">
                <input type="checkbox" :value="tag" v-model="selectedTags" @change="applyFilters()" />
                <span>{{tag}}</span>
              </label>
            </div>
          </div>

          <!-- Vendors -->
          <div v-if="aggregatedFilters.vendors && aggregatedFilters.vendors.length > 0" class="rebuy-smart-collections__filter-section">
            <h4 class="rebuy-smart-collections__filter-title">Vendor</h4>
            <div class="rebuy-smart-collections__filter-options">
              <label v-for="vendor in aggregatedFilters.vendors" class="rebuy-smart-collections__filter-option">
                <input type="checkbox" :value="vendor" v-model="selectedVendors" @change="applyFilters()" />
                <span>{{vendor}}</span>
              </label>
            </div>
          </div>

          <!-- Product Types -->
          <div v-if="aggregatedFilters.productTypes && aggregatedFilters.productTypes.length > 0" class="rebuy-smart-collections__filter-section">
            <h4 class="rebuy-smart-collections__filter-title">Product Type</h4>
            <div class="rebuy-smart-collections__filter-options">
              <label v-for="type in aggregatedFilters.productTypes" class="rebuy-smart-collections__filter-option">
                <input type="checkbox" :value="type" v-model="selectedTypes" @change="applyFilters()" />
                <span>{{type}}</span>
              </label>
            </div>
          </div>

          <!-- Product Options -->
          <div v-for="(values, optionName) in aggregatedFilters.options" class="rebuy-smart-collections__filter-section">
            <h4 class="rebuy-smart-collections__filter-title">{{optionName}}</h4>
            <div class="rebuy-smart-collections__filter-options">
              <label v-for="value in values" class="rebuy-smart-collections__filter-option">
                <input type="checkbox" :value="value" v-model="selectedOptions[optionName]" @change="applyFilters()" />
                <span>{{value}}</span>
              </label>
            </div>
          </div>

          <!-- Metafields -->
          <div v-for="(values, metafieldKey) in aggregatedFilters.metafields" class="rebuy-smart-collections__filter-section">
            <h4 class="rebuy-smart-collections__filter-title">{{formatMetafieldTitle(metafieldKey)}}</h4>
            <div class="rebuy-smart-collections__filter-options">
              <label v-for="value in values" class="rebuy-smart-collections__filter-option">
                <input type="checkbox" :value="value" v-model="selectedMetafields[metafieldKey]" @change="applyFilters()" />
                <span>{{value}}</span>
              </label>
            </div>
          </div>

        </aside>

        <!-- Products Area -->
        <main class="rebuy-smart-collections__main">

          <!-- Mobile Filter Trigger -->
          <div class="rebuy-smart-collections__mobile-controls">
            <button @click="openMobileFilters()" class="rebuy-smart-collections__mobile-filter-btn">
              <rebuy-icon name="filter"></rebuy-icon>
              Filters
              <span v-if="activeFilterCount > 0" class="rebuy-smart-collections__filter-count">{{activeFilterCount}}</span>
            </button>

            <div class="rebuy-smart-collections__mobile-sort">
              <label for="mobile-sort" class="sr-only">Sort by</label>
              <select id="mobile-sort" v-model="sortBy" @change="handleSort()">
                <option v-for="option in sortOptions" :value="option.value">{{option.label}}</option>
              </select>
            </div>
          </div>

          <!-- Desktop Sort -->
          <div class="rebuy-smart-collections__desktop-controls">
            <div class="rebuy-smart-collections__results-count">
              {{totalProducts}} products
            </div>

            <div class="rebuy-smart-collections__sort">
              <label for="desktop-sort">Sort by:</label>
              <select id="desktop-sort" v-model="sortBy" @change="handleSort()">
                <option v-for="option in sortOptions" :value="option.value">{{option.label}}</option>
              </select>
            </div>
          </div>

          <!-- Selected Filters -->
          <div v-if="hasSelectedFilters()" class="rebuy-smart-collections__selected-filters">
            <span v-for="filter in getSelectedFiltersDisplay()" class="rebuy-smart-collections__selected-filter">
              {{filter.label}}
              <button @click="removeFilter(filter)" :aria-label="'Remove ' + filter.label + ' filter'">
                <rebuy-icon name="x"></rebuy-icon>
              </button>
            </span>
          </div>

          <!-- Skeleton Loading -->
          <div v-if="isLoading" class="rebuy-smart-collections__skeleton rebuy-smart-collections__skeleton--grid">
            <div v-for="n in 12" class="rebuy-smart-collections__skeleton-item">
              <div class="rebuy-smart-collections__skeleton-image"></div>
              <div class="rebuy-smart-collections__skeleton-text"></div>
              <div class="rebuy-smart-collections__skeleton-text short"></div>
            </div>
          </div>

          <!-- Products Grid -->
          <div v-else-if="products && products.length > 0" class="rebuy-smart-collections__products-grid">
            <div v-for="(product, index) in products" :key="product.id" class="rebuy-smart-collections__product-card">

              <!-- Product Image -->
              <a :href="productUrl(product)" class="rebuy-smart-collections__product-image" @click="handleProductView(product, index)">
                <img
                  :src="productImage(product)"
                  :srcset="generateImgSrcset(product)"
                  :alt="product.name"
                  loading="lazy"
                />
                <span v-if="product.featured_badge" class="rebuy-smart-collections__badge">{{product.featured_badge}}</span>
              </a>

              <!-- Product Info -->
              <div class="rebuy-smart-collections__product-info">
                <a :href="productUrl(product)" class="rebuy-smart-collections__product-title" @click="handleProductView(product, index)">
                  {{product.name}}
                </a>

                <!-- Reviews -->
                <div v-if="shouldShowReviews(product)" class="rebuy-smart-collections__product-reviews" aria-label="Product rating">
                  <span class="rebuy-star-rating">
                    <span class="rebuy-star-rating-background"></span>
                    <span class="rebuy-star-rating-foreground" :style="{ width: getReviewPercentage(product) }"></span>
                  </span>
                  <span class="rebuy-review-count">({{product.reviews.count}})</span>
                </div>

                <!-- Price -->
                <div class="rebuy-smart-collections__product-price">
                  <span v-if="productOnSale(product)" class="rebuy-money sale">
                    <span class="sr-only">Sale price</span>
                    <span v-html="formatMoney(product.selected_variant.price)"></span>
                  </span>
                  <span v-if="productOnSale(product)" class="rebuy-money compare-at">
                    <span class="sr-only">Original price</span>
                    <span v-html="formatMoney(product.selected_variant.compareAtPrice)"></span>
                  </span>
                  <span v-else class="rebuy-money">
                    <span class="sr-only">Price</span>
                    <span v-html="formatMoney(product.selected_variant.price)"></span>
                  </span>
                </div>

                <!-- Variant Selector -->
                <div v-if="shouldShowVariantSelector(product)" class="rebuy-smart-collections__variant-selector">
                  <label :for="'variant-' + product.id" class="sr-only">Select variant</label>
                  <select :id="'variant-' + product.id" v-model="product.selected_variant_id" @change="selectVariant(product)">
                    <option v-for="variant in product.variants" :value="variant.id">{{variant.name}}</option>
                  </select>
                </div>

                <!-- Add to Cart -->
                <button
                  v-if="shouldShowAddToCart(product)"
                  class="rebuy-button rebuy-smart-collections__add-to-cart"
                  :class="{ working: product.status === 'adding' }"
                  :disabled="!variantAvailable(product.selected_variant) || product.status === 'adding'"
                  :aria-label="buttonAriaLabel(product)"
                  @click="addToCart(product)"
                >
                  <span v-html="buttonLabel(product)"></span>
                </button>
              </div>

            </div>
          </div>

          <!-- No Results -->
          <div v-else class="rebuy-smart-collections__no-results">
            <p>No products found matching your filters.</p>
            <button @click="resetFilters()" class="rebuy-button">Clear Filters</button>
          </div>

          <!-- Pagination -->
          <div v-if="shouldShowPagination()" class="rebuy-smart-collections__pagination">
            <button
              v-if="hasPreviousPage()"
              @click="goToPage(currentPage - 1)"
              class="rebuy-smart-collections__pagination-btn"
              aria-label="Previous page"
            >
              <rebuy-icon name="chevron-left"></rebuy-icon>
              Previous
            </button>

            <div class="rebuy-smart-collections__pagination-pages">
              <button
                v-for="page in visiblePages"
                :key="page"
                @click="goToPage(page)"
                class="rebuy-smart-collections__pagination-page"
                :class="{ active: page === currentPage }"
                :aria-current="page === currentPage ? 'page' : null"
              >
                {{page}}
              </button>
            </div>

            <button
              v-if="hasNextPage()"
              @click="goToPage(currentPage + 1)"
              class="rebuy-smart-collections__pagination-btn"
              aria-label="Next page"
            >
              Next
              <rebuy-icon name="chevron-right"></rebuy-icon>
            </button>
          </div>

          <!-- Load More -->
          <div v-if="shouldShowLoadMore()" class="rebuy-smart-collections__load-more">
            <button @click="loadMore()" :disabled="isLoadingMore" class="rebuy-button">
              {{isLoadingMore ? 'Loading...' : 'Load More Products'}}
            </button>
          </div>

        </main>

      </div>

      <!-- Mobile Filter Flyout -->
      <div v-if="mobileFiltersOpen" class="rebuy-smart-collections__mobile-flyout" role="dialog" aria-modal="true" aria-label="Product filters">
        <div class="rebuy-smart-collections__mobile-flyout-backdrop" @click="closeMobileFilters()"></div>
        <div class="rebuy-smart-collections__mobile-flyout-panel">
          <div class="rebuy-smart-collections__mobile-flyout-header">
            <h3>Filters</h3>
            <button @click="closeMobileFilters()" aria-label="Close filters">
              <rebuy-icon name="x"></rebuy-icon>
            </button>
          </div>
          <div class="rebuy-smart-collections__mobile-flyout-body">
            <!-- Same filter sections as sidebar -->
          </div>
          <div class="rebuy-smart-collections__mobile-flyout-footer">
            <button @click="resetFilters()" class="rebuy-smart-collections__reset-btn">Reset</button>
            <button @click="closeMobileFilters()" class="rebuy-button">Apply Filters</button>
          </div>
        </div>
      </div>

      <!-- Powered by Rebuy -->
      <div v-if="shouldShowPoweredByRebuy()" class="powered-by-rebuy">
        <a :href="'https://rebuyengine.com/?shop=' + shop()" target="_blank" rel="noopener">
          Powered by Rebuy
        </a>
      </div>

    </div>
  </div>
</script>
{% endraw %}

Template Features

Feature Description
Hero section Collection title, description, and optional hero image
Sidebar filters Persistent filter panel with collapsible sections
Mobile flyout Dedicated filter panel for mobile devices
Skeleton loading Placeholder UI while products load
Selected filters Visual display of active filters with remove buttons
Product grid Responsive product cards with images, reviews, pricing
Accessibility ARIA labels, screen reader text, keyboard navigation

Layout Structure

+------------------+------------------------+
|     Hero Section                          |
+------------------+------------------------+
|                  |                        |
|    Sidebar       |    Products Grid       |
|    Filters       |                        |
|                  |    - Sort controls     |
|    - Price       |    - Product cards     |
|    - Availability|    - Pagination        |
|    - Tags        |                        |
|    - Vendors     |                        |
|    - Types       |                        |
|                  |                        |
+------------------+------------------------+

Mobile Considerations

On mobile devices: - Sidebar hides and becomes a flyout panel - Filter button shows active filter count - Flyout includes Apply and Reset actions

Customization

Accessing Liquid

To access Liquid snippets within the template:

{% raw %}
  <!-- Vue.js template code -->
{% endraw %}

{% render 'your-liquid-snippet' %}

{% raw %}
  <!-- More Vue.js template code -->
{% endraw %}

CSS Classes

All elements use BEM-style class names prefixed with rebuy-smart-collections__. Override these in your theme CSS to customize appearance.

See something that needs updating? Suggest an edit