carousel
Everything you need for a modern, performant carousel
Seamless continuous scrolling with automatic cloning
Mobile-friendly swipe gestures and mouse drag support
Breakpoint-based configuration for all screen sizes
Less than 10KB gzipped with zero dependencies
Optional automatic sliding with configurable intervals
Flexible API with extensive configuration options
Simple full-width carousel with infinite loop and autoplay
<div class="carousel">
<div class="carousel__inner">
<div class="carousel__slide">
<img src="banner1.jpg" alt="Banner 1">
</div>
<div class="carousel__slide">
<img src="banner2.jpg" alt="Banner 2">
</div>
<div class="carousel__slide">
<img src="banner3.jpg" alt="Banner 3">
</div>
</div>
</div>
<button class="carousel__arrow carousel__arrow--prev">←</button>
<button class="carousel__arrow carousel__arrow--next">→</button>
<div class="carousel__pagination"></div>
.carousel {
width: 100%;
overflow: hidden;
}
.carousel__inner {
display: flex;
gap: 5px;
transition: transform 0.4s ease;
}
.carousel__slide {
flex-shrink: 0;
width: 100%;
}
.carousel__slide img {
width: 100%;
height: auto;
display: block;
}
.carousel__arrow {
position: absolute;
top: 50%;
z-index: 10;
transform: translateY(-50%);
width: 44px;
height: 44px;
background: #FFFFFF;
border: none;
border-radius: 4px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
transition: all 0.3s ease;
font-weight: 700;
font-size: 22px;
}
.carousel__arrow:hover {
background: #f5f5f5;
transform: translateY(-50%) scale(1.05);
}
.carousel__arrow--prev {
left: 16px;
}
.carousel__arrow--next {
right: 16px;
}
.carousel__pagination {
width: max-content;
position: absolute;
bottom: 15px;
left: 50%;
transform: translateX(-50%);
display: flex;
gap: 8px;
padding: 8px 16px;
background: #FFFFFF;
border-radius: 40px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}
.merrygo-bullet {
width: 8px;
height: 8px;
border-radius: 50%;
background: #CED1D3;
border: none;
cursor: pointer;
transition: all 0.3s ease;
}
.merrygo-bullet-active {
background: #000000;
}
const carousel = new MerryGo({
gallery: document.querySelector('.carousel'),
galleryInner: document.querySelector('.carousel__inner'),
prevBtn: document.querySelector('.carousel__arrow--prev'),
nextBtn: document.querySelector('.carousel__arrow--next'),
pagination: document.querySelector('.carousel__pagination'),
gap: 5,
autoplay: 5000,
infinityLoop: true
});
Multiple slides visible with responsive breakpoints
<div class="products-carousel">
<div class="products-carousel__inner">
<div class="products-carousel__slide">Product 1</div>
<div class="products-carousel__slide">Product 2</div>
<div class="products-carousel__slide">Product 3</div>
<!-- more slides -->
</div>
</div>
<button class="products-carousel__arrow products-carousel__arrow--prev">←</button>
<button class="products-carousel__arrow products-carousel__arrow--next">→</button>
<div class="products-carousel__pagination"></div>
.products-carousel {
overflow: hidden;
user-select: none;
}
.products-carousel__inner {
display: flex;
gap: 20px;
transition: transform 0.4s ease;
}
.products-carousel__slide {
box-sizing: border-box;
flex-shrink: 0;
width: calc((100% - 60px) / 4); /* 4 visible */
}
.products-carousel__arrow {
background-color: #fff;
width: 44px;
height: 44px;
border-radius: 800px;
border: 1px solid #E6E6E6;
box-shadow: 0px 1px 8px 0px #0000001F;
position: absolute;
top: 50%;
transform: translateY(-50%);
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
font-weight: 700;
font-size: 22px;
}
.products-carousel__arrow:hover {
background: #f5f5f5;
transform: translateY(-50%) scale(1.05);
}
.products-carousel__arrow--prev {
left: 16px;
}
.products-carousel__arrow--next {
right: 16px;
}
.products-carousel__pagination {
width: max-content;
position: absolute;
bottom: 15px;
left: 50%;
transform: translateX(-50%);
display: flex;
gap: 8px;
padding: 8px 16px;
background: #FFFFFF;
border-radius: 40px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}
.merrygo-bullet {
width: 8px;
height: 8px;
border-radius: 50%;
background: #CED1D3;
border: none;
cursor: pointer;
transition: all 0.3s ease;
}
.merrygo-bullet-active {
background: #000000;
}
@media (max-width: 1024px) {
.products-carousel__inner {
gap: 15px;
}
.products-carousel__slide {
width: calc((100% - 30px) / 3); /* 3 visible */
}
}
@media (max-width: 768px) {
.products-carousel__slide {
width: calc((100% - 15px) / 2); /* 2 visible */
}
}
@media (max-width: 560px) {
.products-carousel__inner {
gap: 0;
}
.products-carousel__slide {
width: 100%; /* 1 visible */
}
}
const carousel = new MerryGo({
gallery: document.querySelector('.products-carousel'),
galleryInner: document.querySelector('.products-carousel__inner'),
prevBtn: document.querySelector('.products-carousel__arrow--prev'),
nextBtn: document.querySelector('.products-carousel__arrow--next'),
pagination: document.querySelector('.products-carousel__arrow--next'),
infinityLoop: false,
breakpoints: {
0: { slidesVisible: 1, gap: 0 },
561: { slidesVisible: 2, gap: 15 },
769: { slidesVisible: 3, gap: 15 },
1025: { slidesVisible: 4, gap: 20 }
}
});
Synchronized carousel with clickable thumbnail navigation
<!-- Thumbnails -->
<div class="gallery__thumbnails">
<input type="radio" name="thumb" id="thumb-0" checked>
<label class="gallery__thumbnail" for="thumb-0">
<img src="image1.jpg">
</label>
<input type="radio" name="thumb" id="thumb-1" checked>
<label class="gallery__thumbnail" for="thumb-1">
<img src="image2.jpg">
</label>
<input type="radio" name="thumb" id="thumb-2" checked>
<label class="gallery__thumbnail" for="thumb-2">
<img src="image3.jpg">
</label>
</div>
<!-- Main Gallery -->
<div class="gallery">
<div class="gallery__inner">
<div class="gallery__slide">
<img src="image1.jpg">
</div>
<div class="gallery__slide">
<img src="image2.jpg">
</div>
<div class="gallery__slide">
<img src="image3.jpg">
</div>
</div>
</div>
<button class="gallery__arrow gallery__arrow--prev">←</button>
<button class="gallery__arrow gallery__arrow--next">→</button>
.gallery {
overflow: hidden;
display: flex;
gap: 20px;
}
.gallery__inner {
display: flex;
gap: 5px;
transition: transform 0.4s ease;
}
.gallery__slide {
box-sizing: border-box;
flex-shrink: 0;
}
.gallery__arrow {
background-color: #fff;
width: 44px;
height: 44px;
border-radius: 800px;
border: 1px solid #E6E6E6;
box-shadow: 0px 1px 8px 0px #0000001F;
position: absolute;
top: 50%;
transform: translateY(-50%);
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
font-weight: 700;
font-size: 22px;
}
.gallery__arrow:hover {
background: #f5f5f5;
transform: translateY(-50%) scale(1.05);
}
.gallery__arrow--prev {
left: 16px;
}
.gallery__arrow--next {
right: 16px;
}
.gallery__thumbnails {
width: 80px;
min-width: 80px;
display: flex;
flex-direction: column;
gap: 15px;
}
.gallery__thumbnails input[type="radio"] {
display: none;
}
.gallery__thumbnail {
width: 100%;
height: 80px;
border: 3px solid transparent;
border-radius: 8px;
overflow: hidden;
cursor: pointer;
transition: all 0.3s ease;
position: relative;
}
.gallery__thumbnails input:checked + .gallery__thumbnail {
border-color: #000000;
}
.gallery__thumbnail:hover {
border-color: #82898E;
}
.gallery__thumbnail img {
width: 100%;
height: 100%;
object-fit: cover;
display: block;
}
const thumbInputs = Array.from(
document.querySelectorAll('.gallery__thumbnails input[type="radio"]')
);
const carousel = new MerryGo({
gallery: document.querySelector('.gallery'),
galleryInner: document.querySelector('.gallery__inner'),
thumbs: thumbInputs, // Array of radio inputs
gap: 5,
prevBtn: document.querySelector(.gallery__arrow--prev'),
nextBtn: document.querySelector('.gallery__arrow--next'),
});
Install MerryGo and start to create!
<script src="https://cdn.jsdelivr.net/npm/merrygo-carousel@1.0.7/dist/merrygo.js"></script>
npm install merrygo-carousel