Featured Collection with Slider Option

Featured Collection with Slider Option

How to see the code

1. Please log in/create an account first. This is to ensure that all purchases are connected to an account and can be viewed on different devices.

2. Purchase the code using the "purchase box" on the specific page of the desired code.

3. After the purchase, please refresh the page.

Compatability: Dawn 2.0 to Shopify FREE themes.

I created a Collection with numbers and dots (see version here). This time I added a clickable slider option. Please see the checkbox in the section setting and check for the corresponding version. 

NOTE: The quick-view button in the demo is a separate code. Check this link for quick-view button.

Check DEMO store here 💻. Password: made4uo

I have a checkbox available in the theme editor to convert the code to newer or older version of Shopify Dawn Theme. 

To Start:

1. Go to Admin Shopify store > Themes > Actions > Edit Code

2. In Section folder, create a new section, name it "Collection Slider", then replace the default code with the code below.

 {{ 'component-card.css' | asset_url | stylesheet_tag }}
{{ 'component-price.css' | asset_url | stylesheet_tag }}
{{ 'component-product-grid.css' | asset_url | stylesheet_tag }}
{{ 'featured-slider.css' | asset_url | stylesheet_tag }}

<link rel="stylesheet" href="{{ 'component-slider.css' | asset_url }}" media="print" onload="this.media='all'">
<link rel="stylesheet" href="{{ 'template-collection.css' | asset_url }}" media="print" onload="this.media='all'">
<noscript>{{ 'template-collection.css' | asset_url | stylesheet_tag }}</noscript>

{%- liquid
assign products_to_display = section.settings.collection.all_products_count
assign swipe_on_mobile = true

if section.settings.collection.all_products_count > section.settings.products_to_show
assign products_to_display = section.settings.products_to_show
assign more_in_collection = true
endif
-%}

<div class="collectionSlider" style= "padding-top: {{ section.settings.padding_top  | append: "&" }}; padding-bottom: {{section.settings.padding_bottom  | append: "&" }}">
<div class="featured-title-wrapper{% if section.settings.title == blank %} title-wrapper-with-link--no-heading{% endif %}">
{% if section.settings.title != blank %}
<h2 class="featured-title">{{ section.settings.title | escape }}</h2>
{% endif %}
{% if section.settings.show_view_all %}
<a href="{{ section.settings.collection.url }}" class="button">{{ 'sections.featured_collection.view_all' | t }}</a>
{% endif %}
</div>

<collection-slider-component style="--border-color: {{section.settings.border_color}};">
{% if section.settings.slider_visual == 'slider' %}<div class="sliderCounterBox">
<button type="button" class="sliderCounterButton sliderCounterButton--prev slider-button"
data-step="1"
name="previous"
aria-label="{{ 'sections.slideshow.previous_slideshow' | t }}"
style"display: flex"
aria-controls="Slider-{{ section.id }}">{% render 'icon-caret' %}</button>
{% endif %}
<ul id="Slider-{{ section.id }}"
class="featured-grid
product-grid
{% if section.settings.collection.all_products_count > 2 and swipe_on_mobile and section.settings.products_to_show > 2 %}
slider slider--tablet grid--peek{% endif %}
{% if section.settings.show_view_all and section.settings.collection.products.size > section.settings.products_to_show %}
negative-margin--small{% endif %}" role="list">
{%- for product in section.settings.collection.products limit: section.settings.products_to_show -%}
<li id="Slide-{{ section.id }}-{{ forloop.index }}"
data-image="{{forloop.index0}}"
class="grid--col {% if section.settings.collection.all_products_count > 2 and swipe_on_mobile and section.settings.products_to_show > 2 %} slider__slide{% endif %}">
{% if section.settings.newer_version %}
{% render 'card-product',
card_product: product,
media_aspect_ratio: section.settings.image_ratio,
show_secondary_image: section.settings.show_secondary_image,
show_vendor: section.settings.show_vendor,
show_rating: section.settings.show_rating
%}
{% else %}
{% render 'product-card',
product_card_product: product,
media_size: section.settings.image_ratio,
show_secondary_image: section.settings.show_secondary_image,
add_image_padding: section.settings.add_image_padding,
show_vendor: section.settings.show_vendor,
show_image_outline: section.settings.show_image_outline,
show_rating: section.settings.show_rating
%}
{% endif %}
</li>
{%- else -%}
{%- for i in (1..4) -%}
<li class="grid__item">
{% render 'card-product', show_vendor: section.settings.show_vendor %}
</li>
{%- endfor -%}
{%- endfor -%}
</ul>
{% if section.settings.slider_visual == 'slider' %}
<button type="button" class="sliderCounterButton sliderCounterButton--next slider-button {% if section.settings.slider_visual != 'slider' %}hidden {% endif %}"
name="next"
data-step="1"
style="display: flex"
aria-label="{{ 'sections.slideshow.next_slideshow' | t }}"
aria-controls="Slider-{{ section.id }}">{% render 'icon-caret' %}
</button>
</div>
{% endif %}
{%- if section.settings.collection.all_products_count > 2 and swipe_on_mobile and section.settings.products_to_show > 2 -%}

{%- if section.settings.slider_visual == 'slider' -%}
<div class="sliderContainer">
<input type="range" min="0" max="{{products_to_display | minus: 1}}" value="1" class="sliderCounter" id="myRange">
</div>
<style>
.collectionSlider .sliderCounter::-webkit-slider-thumb {
width: calc(100% / {{products_to_display }});
}

.collectionSlider .sliderCounter::-moz-range-thumb {
width: calc(100% / {{products_to_display}});
}
</style>
{% endif %}

<div class="slideshow__controls slider-buttons no-js-hidden {% if section.settings.slider_visual == 'slider' %}hidden {% endif %}"
style="display: flex">
<button type="button" class="slider-button slider-button--prev"
data-step="1"
name="previous"
aria-label="{{ 'sections.slideshow.previous_slideshow' | t }}"
aria-controls="Slider-{{ section.id }}">{% render 'icon-caret' %}</button>
<div class="slider-counter slider-counter--{{ section.settings.slider_visual }}{% if section.settings.slider_visual == 'numbers' %} caption{% endif %}">
<div class="counter--mobile">
<span class="slider-counter--current">1</span>
<span aria-hidden="true"> / </span>
<span class="slider-counter--total">
{% if section.settings.products_to_show < section.settings.collection.products %}
{{section.settings.products_to_show }}
{% else %}
{{section.settings.collection.all_products_count}}
{% endif %}
</span>
</div>
<div class="slideshow__control-wrapper slider">
{%- for product in section.settings.collection.products limit: section.settings.products_to_show -%}
<button class="slider-counter__link slider-counter__link--{{ section.settings.slider_visual }} link"
data-dot="{{forloop.index0}}"
style="padding: 1rem; width: 100%"
aria-label="{{ 'sections.slideshow.load_slide' | t }} {{ forloop.index }} {{ 'general.slider.of' | t }}
{{ forloop.length}}" aria-controls="Slider-{{ section.id }}">
{%- if section.settings.slider_visual == 'numbers' -%}{{ forloop.index }}{% else %}<span class="dot"></span>{%- endif -%}
</button>
{%- endfor -%}
</div>
</div>
<button type="button" class="slider-button slider-button--next"
name="next"
data-step="1"
aria-label="{{ 'sections.slideshow.next_slideshow' | t }}"
aria-controls="Slider-{{ section.id }}">{% render 'icon-caret' %}
</button>
</div>

<noscript>
<div class="slider-buttons" style="display: flex">
<div class="slider-counter">
{%- for product in section.settings.collection.products limit: section.settings.products_to_show -%}
<a href="#Slide-{{ section.id }}-{{ forloop.index }}"
data-dot="{{forloop.index}}"
class="slider-counter__link link" aria-label="{{ 'sections.slideshow.load_slide' | t }} {{ forloop.index }} {{ 'general.slider.of' | t }} {{ forloop.length}}">
{{ forloop.index }}
</a>
{%- endfor -%}
</div>
</div>
</noscript>
{%- endif -%}
</collection-slider-component>
</div>

{% schema %}
{
"name": "Collection Slider",
"tag": "section",
"class": "spaced-section",
"settings": [
{
"type": "checkbox",
"id": "newer_version",
"default": true,
"label": "Dawn version 2.6 and above"
},
{
"type": "text",
"id": "title",
"default": "Featured collection",
"label": "t:sections.featured-collection.settings.title.label"
},
{
"type": "collection",
"id": "collection",
"label": "t:sections.featured-collection.settings.collection.label"
},
{
"type": "range",
"id": "products_to_show",
"min": 2,
"max": 99,
"step": 1,
"default": 4,
"label": "t:sections.featured-collection.settings.products_to_show.label"
},
{
"type": "checkbox",
"id": "show_view_all",
"default": true,
"label": "t:sections.featured-collection.settings.show_view_all.label"
},
{
"type": "header",
"content": "Additional Section padding"
},
{
"type": "range",
"id": "padding_top",
"min": 0,
"max": 99,
"step": 1,
"unit": "%",
"default": 0,
"label": "Section padding top"
},
{
"type": "range",
"id": "padding_bottom",
"min": 0,
"max": 99,
"step": 1,
"unit": "%",
"default": 0,
"label": "Section padding bottom"
},
{
"type": "header",
"content": "t:sections.featured-collection.settings.header.content"
},
{
"type": "select",
"id": "image_ratio",
"options": [
{
"value": "adapt",
"label": "t:sections.featured-collection.settings.image_ratio.options__1.label"
},
{
"value": "portrait",
"label": "t:sections.featured-collection.settings.image_ratio.options__2.label"
},
{
"value": "square",
"label": "t:sections.featured-collection.settings.image_ratio.options__3.label"
}
],
"default": "adapt",
"label": "t:sections.featured-collection.settings.image_ratio.label"
},
{
"type": "checkbox",
"id": "show_secondary_image",
"default": false,
"label": "show secondary image"
},
{
"type": "checkbox",
"id": "add_image_padding",
"default": false,
"label": "add image padding"
},
{
"type": "checkbox",
"id": "show_image_outline",
"default": true,
"label": "show image outline"
},
{
"type": "checkbox",
"id": "show_vendor",
"default": false,
"label": "show vendor"
},
{
"type": "checkbox",
"id": "show_rating",
"default": false,
"label": "show product rating",
"info": "To display a rating, add a product rating app. Learn more"
},
{
"type": "color",
"id": "border_color",
"label": "border color",
"default": "#eee"
},
{
"type": "select",
"id": "slider_visual",
"options": [
{
"value": "dots",
"label": "dots"
},
{
"value": "numbers",
"label": "numbers"
},
{
"value": "slider",
"label": "slider"
}
],
"default": "numbers",
"label": "numbers"
}
],
"presets": [
{
"name": "Collection Slider"
}
]
}
{% endschema %}

 3. Next, we need to add some beauty to it. Open the Asset folder, and "create a new asset." Name it "collection-slider." Then place the code below.

 .collectionSlider {
padding: 5%;
overflow: hidden;
}

.collectionSlider slider-component {
position: relative;
display: block;
}

@media screen and (max-width: 989px) {
.no-js slider-component .slider {
padding-bottom: 3rem;
}
}

.slider__slide {
scroll-snap-align: start;
flex-shrink: 0;
}

@media screen and (max-width: 749px) {
.grid--col {
width: 33%;
}
}

@media screen and (max-width: 481px) {
.grid--col {
width: 50%;
}
}

@media screen and (min-width: 750px) {
.grid--col {
width: 20%;
}
}

.collectionSlider .featured-title-wrapper {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 2rem;
}

.collectionSlider .featured-title {
margin: auto 0;
}

.collectionSlider .featured-grid {
display: flex;
padding: 0;
}

.collectionSlider .featured-grid li {
list-style: none;
}

.collectionSlider .slider.slider--tablet {
position: relative;
flex-wrap: inherit;
overflow-x: auto;
scroll-snap-type: x mandatory;
scroll-behavior: smooth;
scroll-padding-left: 1rem;
-webkit-overflow-scrolling: touch;
margin-bottom: 1rem;
}

.collectionSlider .slider__slide {
padding-bottom: 0;
padding: 0 1rem;
}

@media (prefers-reduced-motion) {
.slider--everywhere {
scroll-behavior: auto;
}
}

.collectionSlider .slider.slider--everywhere .slider__slide {
margin-bottom: 0;
padding-bottom: 0;
scroll-snap-align: center;
}

/* Scrollbar */

.collectionSlider .slider {
scrollbar-color: rgb(var(--color-foreground)) rgba(var(--color-foreground), 0.04);
-ms-overflow-style: none;
scrollbar-width: none;
}

.collectionSlider .slider::-webkit-scrollbar {
height: 0.4rem;
width: 0.4rem;
display: none;
}

.no-js .slider {
-ms-overflow-style: auto;
scrollbar-width: auto;
}

.no-js .slider::-webkit-scrollbar {
display: initial;
}

.collectionSlider .slider::-webkit-scrollbar-thumb {
background-color: rgb(var(--color-foreground));
border-radius: 0.4rem;
border: 0;
}
.collectionSlider .slider::-webkit-scrollbar-track {
background: rgba(var(--color-foreground), 0.04);
border-radius: 0.4rem;
}

.collectionSlider .slider-counter {
margin: 0 1.2rem;
display: flex;
min-width: 2rem;
justify-content: center;
}

@media screen and (max-width: 749px) {
.collectionSlider .slider-counter--dots,
.collectionSlider .slider-counter--numbers {
margin: 0;
}
}


@media screen and (max-width: 749px) {
.collectionSlider .slider-counter__link {
padding: 0.7rem;
}
}

.collectionSlider .slider-counter__link--dots .dot {
width: 1rem;
height: 1rem;
border-radius: 50%;
border: 0.1rem solid rgba(var(--color-foreground), 0.5);
padding: 0;
display: block;
}

.collectionSlider .slider-counter__link--active.slider-counter__link--dots .dot {
background-color: rgb(var(--color-foreground));
}

@media screen and (forced-colors: active) {
.slider-counter__link--active.slider-counter__link--dots .dot {
background-color: CanvasText;
}
}

.slider-counter__link--dots:not(.slider-counter__link--active):hover .dot {
border-color: rgb(var(--color-foreground));
}

.slider-counter__link--dots .dot,
.slider-counter__link--numbers {
transition: transform 0.2s ease-in-out;
}

.slider-counter__link--active.slider-counter__link--numbers,
.slider-counter__link--dots:not(.slider-counter__link--active):hover .dot,
.slider-counter__link--numbers:hover {
transform: scale(1.1);
}

.collectionSlider .slider-counter__link--numbers {
color: rgba(var(--color-foreground), 0.5);
text-decoration: none;
}

.collectionSlider .slider-counter__link--numbers:hover {
color: rgb(var(--color-foreground));
}

.collectionSlider .slider-counter__link--active.slider-counter__link--numbers {
text-decoration: underline;
color: rgb(var(--color-foreground));
}

.collectionSlider .slider-buttons {
display: flex;
align-items: center;
justify-content: center;
}

.collectionSlider .slider-button {
color: rgba(var(--color-foreground), 0.75);
background: transparent;
border: none;
cursor: pointer;
width: 44px;
height: 44px;
display: flex;
align-items: center;
justify-content: center;
}

.slider-button:not([disabled]):hover {
color: rgb(var(--color-foreground));
}

.slider-button .icon {
height: 0.6rem;
}

.slider-button[disabled] .icon {
color: rgba(var(--color-foreground), 0.3);
cursor: not-allowed;
}

.slider-button--next .icon {
transform: rotate(-90deg);
}

.slider-button--prev .icon {
transform: rotate(90deg);
}

.slider-button--next:not([disabled]):hover .icon {
transform: rotate(-90deg) scale(1.1);
}

.slider-button--prev:not([disabled]):hover .icon {
transform: rotate(90deg) scale(1.1);
}

.spaced-section--full-width:last-child featured-slideshow-component:not(.page-width) .slideshow__controls {
border-bottom: none;
}

@media screen and (min-width: 750px) {
.collectionSlider .slideshow__controls {
position: relative;
}
}

slideshow-component:not(.page-width) .slider-buttons {
border-right: 0;
border-left: 0;
}

.collectionSlider .slideshow__control-wrapper {
display: flex;
width: 28rem;
overflow-x: auto;
}

.image--active {
border: 5px solid var(--border-color);
}

.counter--mobile {
display: none;
}

@media only screen and (max-width: 481px) {
.collectionSlider .counter--mobile {
display: flex;
}
.collectionSlider .slideshow__control-wrapper {
display: none;
}
}

.collectionSlider .slider-counter__link {
display: flex;
align-items: center;
justify-content: center;
}

.collectionSlider .smallDot {
width: 0.4rem !important;
height: 0.4rem !important;
}

.collectionSlider .mediumDot {
width: 0.75rem !important;
height: 0.75rem !important;
}


/* slider counter */

.collectionSlider .slidecontainer {
width: 100%;
}

.collectionSlider .sliderCounter {
-webkit-appearance: none;
width: 100%;
height: 5px;
border-radius: 5px;
background: #d3d3d3;
outline: none;
opacity: .7;
-webkit-transition: .2s;
transition: opacity .2s;
}

.sliderCounter:hover {
opacity: 1;
}

.sliderCounter::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
height: 5px;
border-radius: 5px;
background: black;
cursor: pointer;
}

.sliderCounter::-moz-range-thumb {
height: 5px;
border-radius: 5px;
background: black;
cursor: pointer;
}

.sliderCounterBox {
display: flex;
align-items: center;
}

.sliderCounterButton {
display: none;
position: absolute;
background: black !important;
color: white !important;
transition: all .2s ease;
z-index: 10;
}

.collectionSlider:hover .sliderCounterButton--prev{
left: 0;
}

.collectionSlider:hover .sliderCounterButton--next {
right: 0;
}

.sliderCounterButton--prev {
left: -50px;
}

.sliderCounterButton--prev > svg{
transform: rotate(90deg);
}

.sliderCounterButton--next {
right: -50px;
}

.sliderCounterButton--next > svg{
transform: rotate(-90deg);
}

.sliderCounterButton:hover {
transform: scale(1.1);
}

.sliderCounterButton > svg {
height: 2rem !important;
}

@media screen and (max-width: 750px) {
.sliderCounterButton--prev {
left: 0;
}
.sliderCounterButton--next {
right: 0;
}
}



 4. Last thing to do is to add the brain in our section. Still at the Asset folder, open the global.js and add the code below. 

 class CollectionSliderComponent extends HTMLElement {
constructor() {
super();
this.sliderControlWrapper = this.querySelector('.slider-buttons');

this.slider = this.querySelector('[id^="Slider-"]');
this.sliderItems = this.querySelectorAll('[id^="Slide-"]');
this.sliderCounter = this.querySelector('.sliderCounter');
this.currentPageElement = this.querySelector('.slider-counter--current');
this.pageTotalElement = this.querySelector('.slider-counter--total');
this.prevButton = this.querySelector('.slider-button--prev');
this.nextButton = this.querySelector('.slider-button--next');

this.sliderButtonPrev = this.querySelector('.sliderCounterButton--prev');
this.sliderButtonNext = this.querySelector('.sliderCounterButton--next');

this.step = 0;
this.sliderControlWrapper = this.querySelector('.slideshow__control-wrapper');

this.sliderControlLinksArray = Array.from(this.sliderControlWrapper.querySelectorAll('.slider-counter__link'));
this.sliderControlLinksArray.forEach(link => link.addEventListener('click', this.linkToSlide.bind(this)));
this.prevButton.addEventListener('click', this.onButtonClick.bind(this));
this.nextButton.addEventListener('click', this.onButtonClick.bind(this));

if(this.sliderCounter) {
this.sliderButtonPrev.addEventListener('click', this.onButtonClick.bind(this));
this.sliderButtonNext.addEventListener('click', this.onButtonClick.bind(this));

this.sliderCounter.addEventListener('change', this.sliderCounterUpdate.bind(this));
}
}

update(slide) {
this.sliderItems.forEach(image => {
image.classList.remove('image--active');
image.removeAttribute('aria-current');
});

this.currentPageElement.innerHTML = slide + 1;
this.pageTotalElement.innerHTML = this.sliderItems.length;
this.sliderItems[slide].classList.add('image--active');
this.sliderItems[slide].setAttribute('aria-current', true);
this.sliderControlButtons = this.querySelectorAll('.slider-counter__link');
this.sliderControlButtons.forEach(link => {
link.classList.remove('slider-counter__link--active');
link.removeAttribute('aria-current');
});

this.sliderControlButtons[slide].classList.add('slider-counter__link--active');
this.sliderControlButtons[slide].setAttribute('aria-current', true);

this.slideScrollPosition = slide * this.sliderItems[0].clientWidth;

this.slider.scrollTo({
left: this.slideScrollPosition
});

if(this.sliderCounter) {
this.sliderCounter.value = slide;
}

if(this.querySelector('.dot')) {
const controlWidth = this.querySelector(`[data-dot='${0}']`).clientWidth;
const controlOffset = this.querySelector(`[data-dot='${slide}']`).offsetLeft;
this.querySelector(`[data-dot='${slide}']`).scrollIntoView({block: "nearest", inline: "center"});
this.querySelectorAll(`.dot`).forEach(dot => dot.classList.remove('mediumDot'));
this.querySelectorAll(`.dot`).forEach(dot => dot.classList.remove('smallDot'));

if (controlOffset > controlWidth * 10){
if(slide > 4 && slide < this.sliderItems.length - 5) {
this.querySelector(`[data-dot='${slide - 5}'] > .dot`).classList.add('smallDot');
this.querySelector(`[data-dot='${slide - 4}'] > .dot`).classList.add('mediumDot');
}
}

if (controlOffset < (controlWidth * 10) + (controlWidth * (this.sliderItems.length - 1)) ){
if(slide > 4 && slide < this.sliderItems.length - 5) {
this.querySelector(`[data-dot='${slide + 4}'] > .dot`).classList.add('mediumDot');
this.querySelector(`[data-dot='${slide + 5}'] > .dot`).classList.add('smallDot');
}
}
}
}

onButtonClick(event) {
event.preventDefault();
if(event.currentTarget.name === 'next') {
this.step++;
if(this.step > this.sliderItems.length - 1) {
this.step = 0
}
} else {
this.step--;
if(this.step < 0) {
this.step = this.sliderItems.length - 1
}
}
this.currentIndex(this.step);
}

linkToSlide(event) {
const dotIndex = event.currentTarget.dataset.dot;
this.step = dotIndex;
this.currentIndex(this.step);
}

currentIndex(index) {
this.update(index);
}

sliderCounterUpdate(event) {
event.preventDefault();
this.step = this.sliderCounter.value;
this.currentIndex(this.step);
}
}

customElements.define('collection-slider-component', CollectionSliderComponent);

 That's it. Enjoy (",)

Copied!
Back to blog

Leave a comment