Hi Guys,
I would like to replace the slide numbers with dots. I would appreciate your help. Thanks
URL: https://basicbastard.co/products/basic-sweater-black?variant=43547178467564
A user seeks to replace slide numbers with dots on their Shopify product page slider.
A detailed solution is provided involving:
Assets/global.js by replacing the SliderComponent class codeSections/main-product.liquid to replace the slide counter markup with dot-based navigation HTMLThe solution includes code snippets for both JavaScript and Liquid template modifications, with screenshots showing where to locate the relevant code sections.
Follow-up issues:
slider-counter caption code in main-product.liquidSnippets/product-media-gallery.liquidThe discussion remains open with troubleshooting ongoing, as the solution appears theme-dependent and may require adjustments based on specific Shopify theme structure.
Hi Guys,
I would like to replace the slide numbers with dots. I would appreciate your help. Thanks
URL: https://basicbastard.co/products/basic-sweater-black?variant=43547178467564
May I suggest to update code these steps:
class SliderComponent extends HTMLElement {
constructor() {
super();
this.slider = this.querySelector('[id^="Slider-"]');
this.sliderItems = this.querySelectorAll('[id^="Slide-"]');
this.enableSliderLooping = false;
this.currentPageElement = this.querySelector('.slider-counter--current');
this.pageTotalElement = this.querySelector('.slider-counter--total');
this.prevButton = this.querySelector('button[name="previous"]');
this.nextButton = this.querySelector('button[name="next"]');
if (!this.slider || !this.nextButton) return;
this.initPages();
const resizeObserver = new ResizeObserver(entries => this.initPages());
resizeObserver.observe(this.slider);
this.slider.addEventListener('scroll', this.update.bind(this));
this.prevButton.addEventListener('click', this.onButtonClick.bind(this));
this.nextButton.addEventListener('click', this.onButtonClick.bind(this));
this.sliderControlLinksArray = Array.from(this.querySelectorAll('.slider-counter__link'));
this.sliderControlLinksArray.forEach(link => link.addEventListener('click', this.linkToSlide.bind(this)));
}
initPages() {
this.sliderItemsToShow = Array.from(this.sliderItems).filter(element => element.clientWidth > 0);
if (this.sliderItemsToShow.length < 2) return;
this.sliderItemOffset = this.sliderItemsToShow[1].offsetLeft - this.sliderItemsToShow[0].offsetLeft;
this.slidesPerPage = Math.floor((this.slider.clientWidth - this.sliderItemsToShow[0].offsetLeft) / this.sliderItemOffset);
this.totalPages = this.sliderItemsToShow.length - this.slidesPerPage + 1;
this.update();
}
resetPages() {
this.sliderItems = this.querySelectorAll('[id^="Slide-"]');
this.initPages();
}
update() {
const previousPage = this.currentPage;
this.currentPage = Math.round(this.slider.scrollLeft / this.sliderItemOffset) + 1;
if (this.currentPageElement && this.pageTotalElement) {
this.currentPageElement.textContent = this.currentPage;
this.pageTotalElement.textContent = this.totalPages;
}
if (this.currentPage != previousPage) {
this.dispatchEvent(new CustomEvent('slideChanged', { detail: {
currentPage: this.currentPage,
currentElement: this.sliderItemsToShow[this.currentPage - 1]
}}));
}
if (this.enableSliderLooping) return;
if (this.isSlideVisible(this.sliderItemsToShow[0]) && this.slider.scrollLeft === 0) {
this.prevButton.setAttribute('disabled', 'disabled');
} else {
this.prevButton.removeAttribute('disabled');
}
if (this.isSlideVisible(this.sliderItemsToShow[this.sliderItemsToShow.length - 1])) {
this.nextButton.setAttribute('disabled', 'disabled');
} else {
this.nextButton.removeAttribute('disabled');
}
this.sliderControlButtons = this.querySelectorAll('.slider-counter__link');
if (!this.sliderControlButtons.length) return;
this.sliderControlButtons.forEach(link => {
link.classList.remove('slider-counter__link--active');
link.removeAttribute('aria-current');
});
this.sliderControlButtons[this.currentPage - 1].classList.add('slider-counter__link--active');
this.sliderControlButtons[this.currentPage - 1].setAttribute('aria-current', true);
}
isSlideVisible(element, offset = 0) {
const lastVisibleSlide = this.slider.clientWidth + this.slider.scrollLeft - offset;
return (element.offsetLeft + element.clientWidth) <= lastVisibleSlide && element.offsetLeft >= this.slider.scrollLeft;
}
onButtonClick(event) {
event.preventDefault();
const step = event.currentTarget.dataset.step || 1;
this.slideScrollPosition = event.currentTarget.name === 'next' ? this.slider.scrollLeft + (step * this.sliderItemOffset) : this.slider.scrollLeft - (step * this.sliderItemOffset);
this.slider.scrollTo({
left: this.slideScrollPosition
});
}
linkToSlide(event) {
event.preventDefault();
const slideScrollPosition = this.slider.scrollLeft + this.sliderItemOffset * (this.sliderControlLinksArray.indexOf(event.currentTarget) + 1 - this.currentPage);
this.slider.scrollTo({
left: slideScrollPosition
});
}
}
1
/
{{ 'general.slider.of' | t }}
{{ media_count }}
{%- assign featured_media = product.selected_or_first_available_variant.featured_media -%}
{% if section.settings.hide_variants and variant_images contains featured_media.src %}
{% endif %}
{%- for media in product.media -%}
{%- unless media.id == product.selected_or_first_available_variant.featured_media.id -%}
{% if section.settings.hide_variants and variant_images contains media.src %}
{% else %}
{%- endif -%}
{%- endunless -%}
{%- endfor -%}
I think I’m missing something - I can’t find slider-counter caption under main-product.liquid . This code works well for multi-column but I don’t see it under main product, is it under a different location?
Please help me, I have exactly the same problem right now, but your solution doesn’t help me. Maybe I’m doing something wrong? I just don’t even see css in your solution.
Hi @Valeria_16 ,
Could you please let me know your store url and your theme is using?