JSFiddle - React, Tailwind, and code Playground
by rainyjune
HTML
<div class="parentEl">
<div id="container">
<div class="item">1</div>
<div class="item">2</div>
<div class="item">3</div>
<div class="item">4</div>
<div class="item">5</div>
<div class="item">6</div>
<div class="item">7</div>
</div>
<div class="controls">
<button class="toggle" data-toggle="prev">Prev</button>
<button class="toggle" data-toggle="next">Next</button>
</div>
<div class="dots" style="text-align: center"></div>
</div>
CSS
#container {
scroll-snap-type: x mandatory;
display: flex;
overflow-x: scroll;
width: 100%;
}
.item {
border: 1px solid red;
min-width: 33%;
height: auto;
scroll-snap-align: start;
}
#container {
scroll-behavior: smooth;
}
/* Hide the horizontal scroll bar */
/* Hide scrollbar for Chrome, Safari and Opera */
#container::-webkit-scrollbar {
display: none;
}
/* Hide scrollbar for IE, Edge and Firefox */
#container {
-ms-overflow-style: none; /* IE and Edge */
scrollbar-width: none; /* Firefox */
}
/** Controls **/
.controls {
padding: 1em;
text-align: center;
}
.controls button {
background: #aaa;
border: 0;
border-radius: 0.25em;
color: #eee;
padding: 0.5em 1em;
}
.controls button:hover,
.controls button:focus {
background: orange;
}
/* The dots/bullets/indicators */
.dot {
cursor: pointer;
height: 13px;
width: 13px;
margin: 0 2px;
background-color: #bbb;
border-radius: 50%;
display: inline-block;
transition: background-color 0.6s ease;
}
.active, .dot:hover {
background-color: #717171;
}
JavaScript
window.onload = function() {
const parentEl = document.querySelector('.parentEl');
const container = document.querySelector('#container');
const dotsWrapperEl = document.querySelector('.dots');
const items = container.querySelectorAll('.item');
const nextBtn = parentEl.querySelector('.controls [data-toggle="next"]');
const prevBtn = parentEl.querySelector('.controls [data-toggle="prev"]');
let currentIndex = 0;
nextBtn.addEventListener('click', function(e) {
currentIndex = (currentIndex + 1) % items.length;
updateUI();
});
prevBtn.addEventListener('click', function(e) {
currentIndex--;
if (currentIndex < 0) currentIndex = items.length - 1;
updateUI();
});
dotsWrapperEl.addEventListener('click', function(e) {
const target = e.target;
const dotList = dotsWrapperEl.querySelectorAll('.dot');
if (target.classList.contains('dot')) {
const index = getDotIndex(target, dotList);
currentIndex = index;
updateUI();
}
});
function getDotIndex(target, dotList) {
for (let i = 0; i < dotList.length; i++) {
if (dotList[i] === target) return i;
}
return -1;
}
function updateUI() {
dotsWrapperEl.querySelector('.active')?.classList.remove('active');
dotsWrapperEl.querySelectorAll('.dot')[currentIndex].classList.add('active');
const ar = getOrder(currentIndex);
for (let i = 0; i < items.length; i++) {
items[i].style.order = ar[i];
}
items[currentIndex].scrollIntoView({block: "start", inline: "start"});
}
function getOrder(rotateCount = 0) {
const arr = Array.from({length: items.length}, (x, i) => i + 1);
arr.push(arr.shift());
if (rotateCount == 0) return arr;
const ar = arr.splice(items.length - rotateCount, rotateCount);
arr.splice(0, 0, ...ar);
return arr;
}
getOrder();
dotsWrapperEl.innerHTML = '<span class="dot"></span>'.repeat(items.length);
updateUI();
};