Dropdown Template
The dropdown template displays filters in collapsible sections above the product grid, providing a compact interface suitable for all device sizes.
Implementation¶
Create a new snippet (typically named rebuy-smart-collection-template) and paste the template code. Then render the snippet in your 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.
{% raw %}
<script id="rebuy-smart-collection-dropdown-template" type="text/template">
<div v-if="shouldShowCollectionsPage()" id="rebuy-smart-collection-dropdown" class="rebuy-smart-collections">
<!-- Smart Collections -->
<div class="rebuy-smart-collections__page">
<!-- Hero Image -->
<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>
<!-- End Hero Image -->
<!-- Skeleton Loader Products -->
<div v-if="!hasLoadedCollectionProducts && smartCollectionsStatus !== 'error'" class="rebuy-smart-collections-skeleton__dropdown rebuy-smart-collections-skeleton">
<div class="rebuy-smart-collections-skeleton__dropdown-filters-container">
<div class="rebuy-smart-collections-skeleton__dropdown-filter-button rebuy-skeleton-background"></div>
<div class="rebuy-smart-collections-skeleton__dropdown-filter-button rebuy-skeleton-background"></div>
</div>
<div class="rebuy-smart-collections-skeleton__product-container" v-bind:class="resultsGridColumns">
<div v-for="product in Array(12)" class="rebuy-smart-collections-skeleton__product">
<div class="rebuy-smart-collections-skeleton__product-image rebuy-skeleton-background"></div>
<div class="rebuy-smart-collections-skeleton__product-title rebuy-skeleton-background"></div>
<div class="rebuy-smart-collections-skeleton__product-price rebuy-skeleton-background"></div>
</div>
</div>
</div>
<!-- End Skeleton Loader Products -->
<div v-if="smartCollectionsStatus === 'error'">
<p>There was an issue getting Products</p>
</div>
<!-- Main Container -->
<div v-if="hasLoadedCollectionProducts" class="rebuy-smart-collections-dropdown__main-section">
<!-- Filters and Sort By container -->
<div class="rebuy-smart-collections-dropdown__filter-sort-container">
<!-- Dropdown Filters -->
<div class="rebuy-collection-filter">
<div>
<button
aria-label="Open product filters dropdown"
@click.stop="handleToggleFilterModal('product')"
@keydown="(e) => handleKeyboardSubmitPrevent(e)"
@keyup="(e) => handleKeyboardSubmit(e, () => { handleToggleFilterModal('product'); })"
class="filter-title rebuy-button"
tabindex="0"
>
<p>
Product Filters
<rebuy-icon
v-bind:name="productFiltersVisible ? 'chevron-up' : 'chevron-down'"
></rebuy-icon>
</p>
</button>
<div id="filterSelectMenu" v-if="productFiltersVisible" class="rebuy-filter-select-menu">
<button
type="button"
class="rebuy-filter-select-menu__close"
v-on:click="() => { handleToggleFilterModal('product') }"
aria-label="Close Dropdown"
>
<rebuy-icon name="x"></rebuy-icon>
</button>
<!--- Selected Filters -->
<div
v-if="hasSelectedFilters() && shouldShowSelectedFilters()"
class="rebuy-smart-collections__selected-filters rebuy-smart-collections-dropdown__selected-filters"
>
<div
class="rebuy-smart-collections__selected-filters-header rebuy-smart-collections-dropdown__selected-filters-header"
>
<h4 class="rebuy-smart-collections-dropdown__filter-list-title">
Selected Filter
</h4>
<button
v-on:click="resetFilters()"
class="rebuy-smart-collections__selected-filters-reset rebuy-smart-collections-dropdown__selected-filters-reset"
>
Reset
</button>
</div>
<div
class="rebuy-smart-collections__selected-filters-body rebuy-smart-collections-dropdown__selected-filters-body"
>
<div
v-if="hasAdjustedPriceFilter"
class="rebuy-smart-collections__selected-filter-tag rebuy-smart-collections-dropdown__selected-filter-tag"
>
<span class="rebuy-smart-collections__selected-tag-label">
<span>
<span v-html="shopCurrencySymbol()"> </span>
<span v-html="filterPrice.min"></span>
</span>
<span>-</span>
<span>
<span v-html="shopCurrencySymbol()"> </span>
<span v-html="handleMaximumPriceFilterLabel()"> </span>
</span>
</span>
<button
type="button"
class="rebuy-smart-collections__selected-filter-tag-remove rebuy-smart-collections-dropdown__selected-filter-tag-remove"
alt="Remove price filter"
aria-label="Remove price filter"
v-on:click="handleRemovingFilter('price')"
>
<rebuy-icon name="x"></rebuy-icon>
</button>
</div>
<div v-if="hasSelectedFilter('availability')">
<div
class="rebuy-smart-collections__selected-filter-tag rebuy-smart-collections-dropdown__selected-filter-tag"
>
<span
v-html="handleAvailabilityFilterLabel()"
class="rebuy-smart-collections__selected-tag-label"
></span>
<button
type="button"
class="rebuy-smart-collections__selected-filter-tag-remove rebuy-smart-collections-dropdown__selected-filter-tag-remove"
v-bind:aria-label="handleRemovingFilterLabel('availability')"
v-bind:aria-label="handleRemovingFilterLabel('availability')"
v-on:click="handleRemovingFilter('availability')"
>
<rebuy-icon name="x"></rebuy-icon>
</button>
</div>
</div>
<div
v-for="(tag, index) in collectionSearchData.filters.tags"
class="rebuy-smart-collections__selected-filter-tag rebuy-smart-collections-dropdown__selected-filter-tag"
>
<span
v-html="tag"
class="rebuy-smart-collections__selected-tag-label"
></span>
<button
type="button"
class="rebuy-smart-collections__selected-filter-tag-remove rebuy-smart-collections-dropdown__selected-filter-tag-remove"
v-bind:alt="'Remove ' + tag + ' tag filter'"
v-bind:aria-label="'Remove ' + tag + ' tag filter'"
v-on:click="handleRemovingFilter('product-tags', tag)"
>
<rebuy-icon name="x"></rebuy-icon>
</button>
</div>
<div
v-for="(category, index) in collectionSearchData.filters.categories"
class="rebuy-smart-collections__selected-filter-tag rebuy-smart-collections-dropdown__selected-filter-tag"
>
<span
v-html="category"
class="rebuy-smart-collections__selected-tag-label"
></span>
<button
type="button"
class="rebuy-smart-collections__selected-filter-tag-remove rebuy-smart-collections-dropdown__selected-filter-tag-remove"
v-bind:alt="'Remove ' + category + ' product type filter'"
v-bind:aria-label="'Remove ' + category + ' product type filter'"
v-on:click="handleRemovingFilter('product-type', category)"
>
<rebuy-icon name="x"></rebuy-icon>
</button>
</div>
<div
v-for="(vendor, index) in collectionSearchData.filters.vendors"
class="rebuy-smart-collections__selected-filter-tag rebuy-smart-collections-dropdown__selected-filter-tag"
>
<span
v-html="vendor"
class="rebuy-smart-collections__selected-tag-label"
></span>
<button
type="button"
class="rebuy-smart-collections__selected-filter-tag-remove rebuy-smart-collections-dropdown__selected-filter-tag-remove"
v-bind:alt="'Remove ' + vendor + ' vendor filter'"
v-bind:aria-label="'Remove ' + vendor + ' vendor filter'"
v-on:click="handleRemovingFilter('vendor', vendor)"
>
<rebuy-icon name="x"></rebuy-icon>
</button>
</div>
<div
v-for="(option, index) in collectionSearchData.filters.options"
class="rebuy-smart-collections__selected-filter-tag rebuy-smart-collections-dropdown__selected-filter-tag"
>
<span
v-html="formatOptionsFilter(option)"
class="rebuy-smart-collections__selected-tag-label"
></span>
<button
type="button"
class="rebuy-smart-collections__selected-filter-tag-remove rebuy-smart-collections-dropdown__selected-filter-tag-remove"
v-bind:alt="'Remove ' + option + ' option filter'"
v-bind:aria-label="'Remove ' + option + ' option filter'"
v-on:click="handleRemovingFilter('option', option)"
>
<rebuy-icon name="x"></rebuy-icon>
</button>
</div>
<div
v-for="(metafieldValue, index) in collectionSearchData.filters.metafields"
class="rebuy-smart-collections__selected-filter-tag rebuy-smart-collections-dropdown__selected-filter-tag"
>
<span
v-html="getReadableFilterValue(metafieldValue)"
class="rebuy-smart-collections__selected-tag-label"
></span>
<button
type="button"
class="rebuy-smart-collections__selected-filter-tag-remove rebuy-smart-collections-dropdown__selected-filter-tag-remove"
v-bind:alt="handleRemovingFilterLabel('metafields', metafieldValue)"
v-bind:aria-label="handleRemovingFilterLabel('metafields', metafieldValue)"
v-on:click="handleRemovingFilter('metafields', metafieldValue)"
>
<rebuy-icon name="x"></rebuy-icon>
</button>
</div>
</div>
</div>
<!-- End Selected Filters -->
<!-- Filters Options Desktop -->
<ul
v-if="hasLoadedInitialCollection"
class="rebuy-smart-collections__filter-list-container rebuy-smart-collections-dropdown__filter-container"
>
<li
v-for="(filter, index) in mappedAggregateFilters"
v-if="filter.enabled"
class="rebuy-filter-select-menu__list-item"
>
<div
v-if="hasFilterEnabled(filter)"
class="rebuy-smart-collections-sidebar__filter-list-container"
>
<div class="rebuy-smart-collections-sidebar__filter-list-header">
<button
class="rebuy-smart-collections-sidebar__filter-list-toggle"
type="button"
v-bind:alt="filter.isExpanded ? 'Close ' + filter.name : 'Open ' + filter.name"
v-bind:aria-label="filter.isExpanded ? 'Close ' + filter.name : 'Open ' + filter.name"
v-on:click="handleToggleFilterExpansion(filter, index)"
>
<h4
class="rebuy-smart-collections-sidebar__filter-list-title"
v-html="getFilterName(filter)"
></h4>
<div v-if="filterDropDownStyle('plusMinus')">
<rebuy-icon v-if="filter.isExpanded" name="minus"></rebuy-icon>
<rebuy-icon v-if="!filter.isExpanded" name="plus"></rebuy-icon>
</div>
<div v-if="filterDropDownStyle('chevron')">
<rebuy-icon name="chevron-down" v-bind:class="[filter.isExpanded ? 'filter-open' : 'filter-close']"></rebuy-icon>
</div>
</button>
</div>
<div v-if="filter.isExpanded">
<!-- Product Tags Filters -->
<ul
v-if="filter.type === 'product-tags'"
class="rebuy-smart-collections__filter-option rebuy-smart-collections__filter-product-tags"
>
<li
v-for="value in filter.values"
class="rebuy-smart-collections__filter-option-list rebuy-smart-collections-sidebar__filter-list"
>
<input
:id="'rebuy-option-tag-'+ value.tags"
type="checkbox"
class="rebuy-checkbox"
:checked="hasSelectedFilter('product-tags', value.tags)"
v-on:change="handleUpdateSearchQuery(filter.type, value.tags)"
/>
<label
:for="'rebuy-option-tag-'+ value.tags"
class="rebuy-smart-collections__filter-option-checkbox-label"
>
{{ formatTagValue(value.tags) }}
<span
v-if="shouldShowProductFilterCount()"
class="rebuy-smart-collections__filter-label"
>
({{value.numProducts}})
</span>
</label>
</li>
</ul>
<!-- Price filter -->
<div
v-if="filter.type === 'price'"
class="rebuy-smart-collections__filter-option rebuy-smart-collections__filter-price"
>
<div class="rebuy-smart-collections__filter-price-block">
<label
for="rebuy-option-price-from"
v-html="shopCurrencySymbol()"
class="rebuy-smart-collections__filter-price-label"
>
</label>
<input
id="rebuy-option-price-from"
type="number"
class="rebuy-input rebuy-smart-collections__filter-price-input"
placeholder="From"
v-bind:value="filterPrice.min"
min="0"
:max="filterPrice.max"
v-on:change="handleUpdateSearchQuery('price', 'min', {
min: filterPrice.min,
max: filterPrice.max,
price: $event.target.valueAsNumber,
})"
/>
</div>
<div class="rebuy-smart-collections__filter-price-dash">-</div>
<div class="rebuy-smart-collections__filter-price-block">
<label
for="rebuy-option-price-to"
v-html="shopCurrencySymbol()"
class="rebuy-smart-collections__filter-price-label"
>
</label>
<input
id="rebuy-option-price-to"
type="number"
class="rebuy-input rebuy-smart-collections__filter-price-input"
placeholder="To"
v-bind:value="filterPrice.max"
:min="filterPrice.min"
v-on:change="handleUpdateSearchQuery('price', 'max', {
min: filterPrice.min,
max: filterPrice.max,
price: $event.target.valueAsNumber,
})"
/>
</div>
</div>
<!-- Vendor Filters -->
<ul
v-if="filter.type === 'vendor'"
class="rebuy-smart-collections__filter-option rebuy-smart-collections__filter-vendor"
>
<li
v-for="(value, index) in filter.values"
:key="index"
class="rebuy-smart-collections__filter-option-list rebuy-smart-collections-dropdown__filter-list"
>
<input
:id="'rebuy-option-vendor-' + value.vendorAsTag"
type="checkbox"
class="rebuy-checkbox"
:checked="hasSelectedFilter('vendor', value.vendorAsTag)"
v-on:change="handleUpdateSearchQuery(filter.type, value.vendorAsTag)"
/>
<label
:for="'rebuy-option-vendor-' + value.vendorAsTag"
class="rebuy-smart-collections__filter-option-checkbox-label"
>
{{value.vendorAsTag}}
<span
v-if="shouldShowProductFilterCount()"
class="rebuy-smart-collections__filter-label"
>
({{value.numProducts}})
</span>
</label>
</li>
</ul>
<!-- Product availability filter-->
<ul
v-if="filter.type === 'availability'"
class="rebuy-smart-collections__filter-option rebuy-smart-collections__filter-availability"
>
<li
class="rebuy-smart-collections__filter-option-list rebuy-smart-collections-dropdown__filter-list"
>
<label class="rebuy-radio-label">
<input
class="radio-input rebuy-radio"
v-on:click="handleUpdateSearchQuery('availability', 'available')"
:checked="hasSelectedFilter('availability', 'available')"
v-bind:value="true"
type="radio"
v-bind:disabled="!hasInStockAvailabilityFilter(filter.values)"
/>
<span
class="radio-label"
v-bind:class="[!hasInStockAvailabilityFilter(filter.values) ? 'disabled' : '']"
>
Available
<span
v-if="hasInStockAvailabilityFilter(filter.values) && shouldShowProductFilterCount()"
v-html="numsOfAvailabilityFilter(filter.values, 'available')"
class="rebuy-smart-collections__filter-label"
>
</span>
</span>
</label>
</li>
<li
class="rebuy-smart-collections__filter-option-list rebuy-smart-collections-dropdown__filter-list"
>
<label class="rebuy-radio-label">
<input
class="radio-input rebuy-radio"
v-on:click="handleUpdateSearchQuery('availability', 'soldOut')"
:checked="hasSelectedFilter('availability', 'soldOut')"
v-bind:value="false"
type="radio"
v-bind:disabled="!hasSoldOutAvailabilityFilter(filter.values)"
/>
<span
class="radio-label"
v-bind:class="[!hasSoldOutAvailabilityFilter(filter.values) ? 'disabled' : '']"
>
Sold Out
<span
v-if="hasSoldOutAvailabilityFilter(filter.values) && shouldShowProductFilterCount()"
class="rebuy-smart-collections__filter-label"
v-html="numsOfAvailabilityFilter(filter.values, 'soldOut')"
>
</span>
</span>
</label>
</li>
</ul>
<!-- Product-type / Categories-->
<ul
v-if="filter.type === 'product-type'"
class="rebuy-smart-collections__filter-option rebuy-smart-collections__filter-product-type"
>
<li
v-for="value in filter.values"
class="rebuy-smart-collections__filter-option-list rebuy-smart-collections-dropdown__filter-list"
>
<input
:id="'rebuy-option-product-type-' + value.categories"
type="checkbox"
class="rebuy-checkbox"
:checked="hasSelectedFilter('product-type', value.categories)"
v-on:change="handleUpdateSearchQuery(filter.type, value.categories)"
/>
<label
:for="'rebuy-option-product-type-' + value.categories"
class="rebuy-smart-collections__filter-option-checkbox-label"
>
{{value.categories}}
<span
v-if="shouldShowProductFilterCount()"
class="rebuy-smart-collections__filter-label"
>
({{value.numProducts}})
</span>
</label>
</li>
</ul>
<!-- Product Option filter-->
<ul
v-if="filter.type === 'product-options'"
class="rebuy-smart-collections__filter-option rebuy-smart-collections__filter-product-option"
>
<li
v-for="(optionGroupValue, key) in filter.values"
class="rebuy-smart-collections__filter-option-list"
>
<input
:id="'rebuy-option-product-type-' + key"
type="checkbox"
class="rebuy-checkbox"
:checked="hasSelectedFilter('product-options', getProductOptionFilterString(filter, key))"
v-on:change="handleUpdateSearchQuery('product-options', getProductOptionFilterString(filter, key), key)"
/>
<label
:for="'rebuy-option-product-type-' + key"
class="rebuy-smart-collections__filter-option-checkbox-label"
>
{{key}}
<span
v-if="shouldShowProductFilterCount()"
class="rebuy-smart-collections__filter-label"
>
({{optionGroupValue.numProducts}})
</span>
</label>
</li>
</ul>
<!-- Product metafield filter-->
<ul
v-if="filter.type === 'product-metafield' || filter.type === 'variant-metafield'"
class="rebuy-smart-collections__filter-option rebuy-smart-collections__filter-product-type"
>
<li
v-for="metafieldValue in filter.values"
class="rebuy-smart-collections__filter-option-list rebuy-smart-collections-dropdown__filter-list"
>
<input
:id="'rebuy-metafield-' + filter.type + '-' + filter.key + '-' + metafieldValue.value"
type="checkbox"
class="rebuy-checkbox"
:checked="hasSelectedFilter(filter.type, getMetafieldFilterString(filter, metafieldValue))"
v-on:change="handleUpdateSearchQuery(filter.type, getMetafieldFilterString(filter, metafieldValue), metafieldValue.readableValue ?? metafieldValue.value)"
/>
<label
:for="'rebuy-metafield-' + filter.type + '-' + filter.key + '-' + metafieldValue.value"
class="rebuy-smart-collections__filter-option-checkbox-label"
>
<span
v-html="metafieldValue.readableValue ? metafieldValue.readableValue : metafieldValue.value"
></span>
<span
v-if="shouldShowProductFilterCount()"
class="rebuy-smart-collections__filter-label"
>
({{metafieldValue.numProducts}})
</span>
</label>
</li>
</ul>
<div v-if="filter?.key !== 'price' && filter?.values?.length === 0">
<p>No available filters</p>
</div>
</div>
</div>
</li>
</ul>
</div>
</div>
</div>
<div v-if="shouldShowSortBy()">
<div
class="rebuy-smart-search-results-page__sort-by rebuy-smart-search-results-page-dropdown__sort-by"
v-if="sortByStyle() === 'sortBySelect'"
>
<label
for="rebuy-smart-collections-sort-options"
class="rebuy-smart-collections-sidebar__sort-by-label"
>
Sort By
</label>
<select
id="rebuy-smart-collections-sort-options"
class="rebuy-select"
v-model="collectionSearchData.sortBy.field"
v-on:change="($event) => handleUpdateSearchQuery('sort_by', $event.target.value)"
>
<option
v-for="option in settings.sortOptions"
value="sort_by"
v-if="option.enabled"
v-bind:value="option.key"
>
{{ option.label || option.name }}
</option>
</select>
</div>
<div
v-if="sortByStyle() === 'sortByDropdown'"
class="rebuy-smart-collections__dropdown-menu-container"
>
<button
aria-label="Open product sorting dropdown"
@click.stop="handleToggleFilterModal('sort')"
@keydown="(e) => handleKeyboardSubmitPrevent(e)"
@keyup="(e) => handleKeyboardSubmit(e, () => { handleToggleFilterModal('sort'); })"
class="rebuy-smart-collections__dropdown-menu-trigger"
>
Sort By:
<span class="rebuy-smart-collections__dropdown-menu-title">
{{getSortByLabel(collectionSearchData.sortBy.field)}}
</span>
<rebuy-icon name="chevron-down" v-bind:class="[sortFiltersVisible ? 'filter-open' : 'filter-close']"></rebuy-icon>
</button>
<ul
id="sortSelectMenu"
v-if="sortFiltersVisible"
class="rebuy-smart-collections__dropdown-menu"
>
<li
v-for="filter in getSortFilters()"
v-if="filter.enabled"
class="rebuy-smart-collections__dropdown-menu-list-item"
:class="{'rebuy-smart-collections__dropdown-menu-list-item--active': collectionSearchData.sortBy.field === filter.key}"
@click="handleUpdateSearchQuery('sort_by', filter.key)"
@keydown="(e) => handleKeyboardSubmitPrevent(e)"
@keyup="(e) => handleKeyboardSubmit(e, () => { handleUpdateSearchQuery('sort_by', filter.key); })"
tabindex="0"
>
{{filter.label || filter.name}}
</li>
</ul>
</div>
</div>
</div>
<!-- Collection Products -->
<div class="rebuy-smart-collections__container-products" v-bind:class="[resultsGridColumns, productListColumnClass()]">
<div v-if="collectionProducts?.length === 0">
<p>No products found</p>
</div>
<div
v-if="hasLoadedInitialCollection && collectionProducts?.length > 0"
v-for="(product, index) of collectionProducts"
:id="'rebuy-product-id-'+ product.id"
:key="product.id + '-product-' + index"
class="rebuy-smart-collections__product rebuy-smart-collections-sidebar__product"
:class="productImageRatio()"
>
<div v-if="shouldRenderPromoTile(product)" class="rebuy-smart-collections__promo-tile">
<a
v-if="shouldRenderPromoTileAnchor(product)"
v-bind:href="product.content.imageRedirectUrl"
class="rebuy-smart-collections__promo-tile rebuy-product-media rebuy-smart-collections__product-media rebuy-smart-collections__absolute-image-container"
>
<img
v-bind:src="product.content.imageUrl"
alt="promo tile"
class="rebuy-smart-collections__promo-tile-image rebuy-smart-collections__product-image rebuy-smart-collections__absolute-image"
:class="hasImageLoaded(product)"
/>
</a>
<div
v-else
class="rebuy-smart-collections__promo-tile rebuy-product-media rebuy-smart-collections__product-media rebuy-smart-collections__absolute-image-container"
>
<img
v-bind:src="product.content.imageUrl"
alt="promo tile"
class="rebuy-smart-collections__promo-tile-image rebuy-smart-collections__product-image rebuy-smart-collections__absolute-image"
:class="hasImageLoaded(product)"
/>
</div>
</div>
<!-- Image container -->
<a
v-if="shouldRenderProduct(product)"
class="rebuy-product-media rebuy-smart-collections__product-media rebuy-smart-collections__absolute-image-container"
v-bind:href="learnMoreURL(product)"
v-on:click="learnMore(product, index)"
v-bind:alt="'View ' + product.name"
>
<div
v-if="shouldShowFeaturedBadge(product)"
class="rebuy-smart-collections__promoted-tag"
v-html="getFeaturedBadgeHtml()"
></div>
<img
v-bind:src="getProductImage(product, product.selected_variant)"
v-bind:srcset="generateImgSrcset(product)"
class="rebuy-smart-collections__product-image rebuy-smart-collections__absolute-image rebuy-smart-collections__absolute-image--zoomed"
:class="hasImageLoaded(product)"
v-bind:alt="'Image of ' + product.name"
/>
</a>
<!-- Product Info -->
<div v-if="shouldRenderProduct(product)" class="rebuy-smart-collections__product-detail">
<div class="rebuy-product-info">
<!-- Product Title -->
<a
class="rebuy-product-title"
v-bind:href="learnMoreURL(product)"
v-on:click="learnMore(product, index)"
v-html="product.name"
v-bind:alt="'View ' + product.name"
>
</a>
<!-- Product Review -->
<div
class="rebuy-product-review"
v-if="shouldDisplayResultsPageProductRating(product)"
aria-label="product star rating"
>
<span class="rebuy-star-rating">
<span
v-if="product.reviews.star_rating"
class="rebuy-star-rating-value sr-only"
v-html="product.ratings.average + ' stars out of 5 stars'"
>
</span>
<span class="rebuy-star-rating-background"></span>
<span
class="rebuy-star-rating-foreground"
v-bind:style="{ width: getProductReviewRatingPercentage(product) }"
></span>
</span>
<span class="rebuy-review-count" v-html="getProductReviewCountHtml(product)"></span>
</div>
<!-- Product Price -->
<div class="rebuy-product-price">
<div v-if="productOnSale(product)">
<span class="rebuy-money sale">
<span class="sr-only">Sale price</span>
<span v-html="formatMoney(product.selected_variant?.price)"></span>
</span>
<span class="rebuy-money compare-at">
<span class="sr-only">Original price</span>
<span v-html="formatMoney(product.selected_variant?.compareAtPrice)"></span>
</span>
</div>
<div v-if="!productOnSale(product)">
<span class="rebuy-money">
<span class="sr-only">Price</span>
<span v-html="formatMoney(product.selected_variant?.price)"></span>
</span>
</div>
</div>
</div>
<!-- Product Options -->
<div class="rebuy-product-options" v-if="shouldShowVariantSelector(product)">
<select
title="Select product variant"
id="rebuy-smart-collections-results-variant-select"
class="rebuy-select"
v-bind:aria-label="'variant of ' + product.name"
v-model="product.selected_variant_id"
v-on:change="selectVariant(product)"
>
<option
v-for="variant in product.variants"
v-bind:value="variant.id"
v-html="variant.name"
></option>
</select>
</div>
<!-- Add-to-cart -->
<div class="rebuy-product-actions" v-if="shouldShowAddToCart(product)">
<button
class="rebuy-button rebuy-smart-collections__cta"
v-bind:class="{ working: (product.status != 'ready' && product.status != 'selecting') }"
v-bind:disabled="!(variantAvailable(product.selected_variant)) || (product.status != 'ready' && product.status != 'selecting')"
v-bind:aria-label="buttonAriaLabel(product)"
v-on:click="addToCart(product)"
type="button"
>
<span v-html="buttonLabel(product)"></span>
</button>
</div>
</div>
</div>
</div>
<!-- End Collection Products -->
<!--- Pagination -->
<div
v-if="shouldRenderDefaultPagination()"
class="rebuy-smart-collections__pagination rebuy-smart-collections-sidebar__pagination-section"
v-bind:class="shouldDisplayAmountPerPage() ? 'rebuy-smart-collections__range' : ''"
>
<!--- Range Selection -->
<div v-if="shouldDisplayAmountPerPage()" class="rebuy-range-selection">
<label
class="rebuy-range-selection-label"
v-bind:class="isAmountPerPageSelectionDisabled() && 'rebuy-range-selection-disabled'"
>
Per page
</label>
<select
title="Select products per page"
id="rebuy-smart-collections-results-per-page-select"
class="rebuy-select"
v-bind:class="isAmountPerPageSelectionDisabled() && 'rebuy-range-selection-disabled'"
aria-label="products per page"
v-model="productPageSizeCount"
v-on:change="handleUpdatePaginationRange($event.target.value)"
v-bind:disabled="isAmountPerPageSelectionDisabled()"
>
<option
v-for="productsPerPage in pageRangeSelection()"
v-bind:value="productsPerPage.value"
>
{{productsPerPage.value}}
</option>
</select>
</div>
<!--- Page Selection -->
<ul
class="rebuy-smart-collections__pagination rebuy-smart-collections-sidebar__pagination"
>
<li class="rebuy-smart-collections__pagination-label">
<button
v-bind:disabled="smartCollectionsStatus === 'loading'"
v-on:click="handleUpdatingPageCount('decrement')"
class="rebuy-smart-collections__pagination-page rebuy-smart-collections__pagination-arrow"
v-bind:class="{
'rebuy-smart-collections__pagination-arrow--disabled': parseInt(collectionSearchData.currentPage) === 1
}"
>
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="currentColor"
>
<path
d="M15.7049 7.41L14.2949 6L8.29492 12L14.2949 18L15.7049 16.59L11.1249 12L15.7049 7.41Z"
fill="currentColor"
/>
</svg>
</button>
</li>
<li
v-for="(pageNumber, index) in handleGeneratingPageList()"
:key="pageNumber + '-pagination-' + index"
class="rebuy-smart-collections__pagination-label"
v-bind:class="[parseInt(pageNumber) === parseInt(collectionSearchData.currentPage) ? 'active' : '']"
>
<button
v-on:click="handleUpdatingPageCount('manual', pageNumber)"
@keydown="(e) => handleKeyboardSubmitPrevent(e)"
@keyup="(e) => handleKeyboardSubmit(e, () => { handleUpdatingPageCount('manual', pageNumber); })"
class="rebuy-smart-collections__pagination-page"
v-bind:disabled="smartCollectionsStatus === 'loading'"
>
<span v-if="pageNumber"> {{ pageNumber }} </span>
<span v-if="!pageNumber" class="rebuy-smart-collections__pagination-icon--disabled">
<rebuy-icon name="more-horizontal" class="rebuy-button-icon"></rebuy-icon>
</span>
</button>
</li>
<li class="rebuy-smart-collections__pagination-label">
<button
v-bind:disabled="smartCollectionsStatus === 'loading'"
v-on:click="handleUpdatingPageCount('increment')"
class="rebuy-smart-collections__pagination-page rebuy-smart-collections__pagination-arrow"
v-bind:class="{
'rebuy-smart-collections__pagination-arrow--disabled': parseInt(collectionSearchData.currentPage) === parseInt(collectionSearchData.searchResultsHeaderMetaData?.['search-page-total'])
}"
>
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="currentColor"
>
<path
d="M9.70492 6L8.29492 7.41L12.8749 12L8.29492 16.59L9.70492 18L15.7049 12L9.70492 6Z"
fill="currentColor"
/>
</svg>
</button>
</li>
</ul>
</div>
<!--- Load More button -->
<div v-if="shouldRenderLoadMore()" class="rebuy-smart-collections__continuous-scroll">
<button
v-if="!hasReachedLastPage()"
v-on:click="handleUpdatingPageCount('continuous')"
class="rebuy-button rebuy-smart-collections__continuous-scroll-button"
v-bind:disabled="smartCollectionsStatus === 'loading'"
>
{{ getLoadMoreText() }}
</button>
</div>
<!--- Continuous Scroll loading spinner -->
<div v-if="shouldRenderContinuousScroll()" class="rebuy-smart-collections__continuous-scroll">
<div
v-if="smartCollectionsStatus === 'loading'"
class="rebuy-smart-collections__continuous-scroll-loader"
>
<span> </span>
</div>
</div>
<!--- End Pagination -->
</div>
</div>
</div>
</script>
{% endraw %}
Template Features¶
| Feature | Description |
|---|---|
| Hero section | Collection title, description, and optional image |
| Skeleton loading | Placeholder UI while products load |
| Filter dropdowns | Collapsible filter panel with price, availability, tags, vendors, product types, product options, metafields |
| Selected filters | Visual display of active filters with individual remove buttons and reset |
| Sort controls | Select dropdown or custom dropdown-menu style sorting |
| Product grid | Responsive product cards with images, reviews, pricing, and promo tiles |
| Variant selector | Dropdown for multi-variant products |
| Add to cart | Configurable add-to-cart buttons with availability states |
| Pagination | Page numbers, load more button, or continuous scroll |
| Per-page selector | Configurable products-per-page dropdown |
Customization¶
Accessing Liquid¶
To access Liquid snippets within the template, end the raw block temporarily:
{% 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-dropdown__ and rebuy-smart-collections__. Override these in your theme CSS to customize appearance.