JS – Responsive pagination slider

Pagination in Views is one of the most powerful and flexible features of Toolset Views. It provides several options to achieve different layouts, such as a typical blog grid with pagination, an article slider, a multi-article slider, or an image slider. It is also great for website optimization, as it prevents loading all entries at once and only loads the entries for the current page. Additionally, it handles URL updates and SEO efficiently.

However, one of its few drawbacks is that it is not fully responsive. It is not possible to adjust the number of paginated items based on the viewport size. Also, it is not possible to change the number of paginated items dynamically using attributes like Limit and Offset.

To work around this limitation, you can implement a responsive pagination slider using JavaScript, especially when you want to load a limited number of entries. This is useful, for example, when creating a multi-article slider, where you display 4 articles per row on desktop, 2 or 3 articles per row on tablet, and just 1 article per row on mobile. In such cases, it’s a good idea to limit the view to load only the latest 8 or 12 articles.

[wpv-layout-start]
	[wpv-items-found]
<div class="my-slider-container">
  <div class="my-slider-grid">
	<!-- wpv-loop-start -->
	<wpv-loop>
      <div class="my-slider-column">
          [wpv-post-body view_template="my-item"]
      </div>
	</wpv-loop>
	<!-- wpv-loop-end -->
	</div>
    <div class="my-slider-pagination">
      <div class="my-slider-page-item page-item-prev">
        <a class="my-slider-page-link prev-arrow" href="#">&#10094;</a>
      </div>
      <div class="my-slider-page-item page-item-next">
        <a class="my-slider-page-link next-arrow" href="#">&#10095;</a>
      </div>
    </div>
  </div>
	[/wpv-items-found]
	[wpv-no-items-found][/wpv-no-items-found]
[wpv-layout-end]


In the JS editor, you will need to add the following code:

// Custom pagination slider

document.addEventListener("DOMContentLoaded", function () {
  const sliders = document.querySelectorAll(".my-slider-container");

  sliders.forEach(sliderContainer => {
    const slider = sliderContainer.querySelector(".my-slider-grid");
    const prevArrow = sliderContainer.querySelector(".prev-arrow");
    const nextArrow = sliderContainer.querySelector(".next-arrow");

    let currentSlide = 0;
    let itemsPerPage = 4; // Default for large screens
    let startX = 0;
    let endX = 0;
    let isSwiping = false;
    let isDragging = false; // Flag to check if the user is dragging

    function updateSlider() {
      let width = window.innerWidth;

      if (width <= 599) {
        itemsPerPage = 1;
      } else if (width <= 980) {
        itemsPerPage = 2;
      } else {
        itemsPerPage = 4;
      }

      const slideWidth = sliderContainer.clientWidth / itemsPerPage;
      slider.style.transform = `translateX(-${currentSlide * slideWidth}px)`;

      // Hide/show arrows based on current slide position
      if (currentSlide === 0) {
        prevArrow.style.display = 'none';
      } else {
        prevArrow.style.display = 'block';
      }

      const totalItems = slider.children.length;
      if (currentSlide >= totalItems - itemsPerPage) {
        nextArrow.style.display = 'none';
      } else {
        nextArrow.style.display = 'block';
      }
    }

    // Arrow click event listeners
    nextArrow.addEventListener("click", function (e) {
      e.preventDefault();
      const totalItems = slider.children.length;
      if (currentSlide < totalItems - itemsPerPage) {
        currentSlide++;
        updateSlider();
      }
    });

    prevArrow.addEventListener("click", function (e) {
      e.preventDefault();
      if (currentSlide > 0) {
        currentSlide--;
        updateSlider();
      }
    });

    // Touch event listeners for mobile swipe functionality
    slider.addEventListener("touchstart", function (e) {
      startX = e.touches[0].clientX;
      isSwiping = true;
      isDragging = false; // Reset dragging flag on touchstart
    });

    slider.addEventListener("touchmove", function (e) {
      if (isSwiping) {
        endX = e.touches[0].clientX;
        if (Math.abs(endX - startX) > 10) { // Only consider as drag if moved more than 10px
          isDragging = true;
        }
      }
    });

    slider.addEventListener("touchend", function (e) {
      if (isSwiping && isDragging) { // Trigger swipe only if there was a drag
        const swipeDistance = endX - startX;
        const threshold = 50; // Minimum swipe distance to trigger

        if (Math.abs(swipeDistance) > threshold) {
          if (swipeDistance > 0) {
            // Swipe right (previous)
            if (currentSlide > 0) {
              currentSlide--;
            }
          } else {
            // Swipe left (next)
            const totalItems = slider.children.length;
            if (currentSlide < totalItems - itemsPerPage) {
              currentSlide++;
            }
          }
          updateSlider();
        }
      }
      isSwiping = false;
    });

    window.addEventListener("resize", updateSlider);
    updateSlider(); // Initialize on page load
  });
});