How can I replace slide numbers with dots on my website?

Topic summary

A user seeks to replace slide numbers with dots on their Shopify product page slider.

A detailed solution is provided involving:

  • Modifying Assets/global.js by replacing the SliderComponent class code
  • Updating Sections/main-product.liquid to replace the slide counter markup with dot-based navigation HTML

The solution includes code snippets for both JavaScript and Liquid template modifications, with screenshots showing where to locate the relevant code sections.

Follow-up issues:

  • One user cannot locate the slider-counter caption code in main-product.liquid
  • Suggested alternative location: Snippets/product-media-gallery.liquid
  • Another user reports the solution doesn’t work for them and notes the absence of CSS in the provided fix

The discussion remains open with troubleshooting ongoing, as the solution appears theme-dependent and may require adjustments based on specific Shopify theme structure.

Summarized with AI on October 24. AI used: claude-sonnet-4-5-20250929.

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:

  1. Go to Store Online-> theme → edit code
  2. Assets/global.js
  3. find class class SliderComponent after that replace with code below
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. Sections/main-product.liquid
  2. find code below

  1
   / 
  {{ 'general.slider.of' | t }}
  {{ media_count }}

  1. Replace code of step 5 with code below

  

    {%- 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 -%}
  

1 Like

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?

Hi @PYZ ,

You try to find it in Snippets/product-media-gallery.liquid

1 Like

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?