
A Netflix-inspired infinite carousel slider written in vanilla JavaScript.
More Features:
- Touch-enabled.
- Navigation arrows.
- Smooth hover effect.
See Also:
How to use it:
1. Load the needed Font Awesome iconic font in the document.
<script src="https://kit.fontawesome.com/a0043d9bc2.js" crossorigin="anonymous"></script>
2. Build the HTML structure for the carousel slider.
<div class="container">
<button type="button" id="moveLeft" class="btn-nav">
ᐊ
</button>
<div class="container-indicators">
<div class="indicator active" data-index=0></div>
<div class="indicator" data-index=1></div>
<div class="indicator" data-index=2></div>
</div>
<div class="slider" id="mySlider">
<div class="movie" id="movie0">
<img src="movie1.jpg" alt="" srcset="" />
<div class="description">
<div class="description__buttons-container">
<div class="description__button"><i class="fas fa-play"></i></div>
<div class="description__button"><i class="fas fa-plus"></i></div>
<div class="description__button"><i class="fas fa-thumbs-up"></i></div>
<div class="description__button"><i class="fas fa-thumbs-down"></i></div>
<div class="description__button"><i class="fas fa-chevron-down"></i></div>
</div>
<div class="description__text-container">
<span class="description__match">97% Match</span>
<span class="description__rating">TV-14</span>
<span class="description__length">2h 11m</span>
<br><br>
<span>Explosive</span>
<span>·</span>
<span>Exciting</span>
<span>·</span>
<span>Family</span>
</div>
</div>
</div>
</div>
<button type="button" id="moveRight" class="btn-nav">
ᐅ
</button>
</div>3. The necessary CSS/CSS3 styles.
:root {
--movie-width: 15.5vw;
--movie-height: 200px;
--arrow-width: 50px;
--slider-py: 200px;
}
@media only screen and (max-width: 1000px) {
:root {
--movie-width: 25vw;
}
}
/*
*
* THE SLIDER CONTAINER
*
*********************************/
.slider {
width: 100%;
overflow-x: scroll;
overflow-y: visible;
white-space: nowrap;
position: relative;
padding-top: var(--slider-py);
padding-bottom: var(--slider-py);
}
/*
*
* SLIDER INDICATORS
*
*********************************/
.container-indicators {
width: 100px;
position: absolute;
right: 0;
top: calc(var(--slider-py) - 60px);
visibility: hidden;
}
.indicator {
width: 15px;
height: 2px;
background-color: grey;
display: inline-block;
}
.indicator.active {
background-color: white;
}
/*
*
* MOVIE ELEMENTS!
*
*********************************/
.movie {
width: var(--movie-width);
height: var(--movie-height);
display: inline-block;
position: relative;
color: white;
padding: 0 2px;
font-size: 0.8rem;
transition: all 0.8s ease-in-out;
}
.movie:nth-of-type(1) {
margin-left: var(--arrow-width);
}
.movie:hover {
transform: scale(1.3);
z-index: 2;
}
.movie img {
object-fit: cover;
height: 100%;
width: 100%;
border-radius: 10px;
}
.description {
position: absolute;
display: none;
z-index: 9999;
background-color: #272727;
width: var(--movie-width);
margin-top: -10px;
padding: 10px 0;
border-bottom-left-radius: 10px;
border-bottom-right-radius: 10px;
}
/* Make description visible when movie is hovered */
.movie:hover > .description {
display: block;
}
.movie:hover > img {
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
}
.description__buttons-container {
display: flex;
flex-direction: row;
padding: 10px;
}
.description__text-container {
padding: 10px;
}
.description__match {
color: green;
}
.description__rating {
outline: 1px solid white;
padding: 0 3px;
margin: 0 5px;
}
.description__button {
display: flex;
align-items: center;
justify-content: center;
width: 20px;
height: 20px;
border: 2px solid white;
text-align: center;
font-size: 8px;
margin-right: 5px;
border-radius: 100%;
}
.description__button:hover {
border-color: grey;
color: grey;
cursor: pointer;
}
.description__button:nth-of-type(5) {
margin-left: auto;
margin-right: 0;
}
/*
*
* BUTTONS
*
*********************************/
.btn-nav {
width: var(--arrow-width);
height: var(--movie-height);
border-radius: 5px;
position: absolute;
bottom: 0;
background-color: rgba(0, 0, 0, 0.3);
outline: none;
border: none;
color: white;
top: var(--slider-py);
z-index: 5;
visibility: hidden;
}
#moveLeft {
left: 0;
}
#moveRight {
right: 0;
}
.container:hover .btn-nav,
.container:hover .container-indicators {
visibility: visible;
}4. The JavaScript to enable the carousel slider.
const slider = document.querySelector(".slider");
const btnLeft = document.getElementById("moveLeft");
const btnRight = document.getElementById("moveRight");
const indicators = document.querySelectorAll(".indicator");
let baseSliderWidth = slider.offsetWidth;
let activeIndex = 0; // the current page on the slider
let movies = [
{
src: "movie1.jpg",
},
{
src: "movie2.jpg",
},
{
src: "movie3.jpg",
},
// ...
];
// Fill the slider with all the movies in the "movies" array
function populateSlider() {
movies.forEach((image) => {
// Clone the initial movie thats included in the html, then replace the image with a different one
const newMovie = document.getElementById("movie0");
let clone = newMovie.cloneNode(true);
let img = clone.querySelector("img");
img.src = image.src;
slider.insertBefore(clone, slider.childNodes[slider.childNodes.length - 1]);
});
}
populateSlider();
populateSlider();
// delete the initial movie in the html
const initialMovie = document.getElementById("movie0");
initialMovie.remove();
// Update the indicators that show which page we're currently on
function updateIndicators(index) {
indicators.forEach((indicator) => {
indicator.classList.remove("active");
});
let newActiveIndicator = indicators[index];
newActiveIndicator.classList.add("active");
}
// Scroll Left button
btnLeft.addEventListener("click", (e) => {
let movieWidth = document.querySelector(".movie").getBoundingClientRect()
.width;
let scrollDistance = movieWidth * 6; // Scroll the length of 6 movies. TODO: make work for mobile because (4 movies/page instead of 6)
slider.scrollBy({
top: 0,
left: -scrollDistance,
behavior: "smooth",
});
activeIndex = (activeIndex - 1) % 3;
console.log(activeIndex);
updateIndicators(activeIndex);
});
// Scroll Right button
btnRight.addEventListener("click", (e) => {
let movieWidth = document.querySelector(".movie").getBoundingClientRect()
.width;
let scrollDistance = movieWidth * 6; // Scroll the length of 6 movies. TODO: make work for mobile because (4 movies/page instead of 6)
console.log(`movieWidth = ${movieWidth}`);
console.log(`scrolling right ${scrollDistance}`);
// if we're on the last page
if (activeIndex == 2) {
// duplicate all the items in the slider (this is how we make 'looping' slider)
populateSlider();
slider.scrollBy({
top: 0,
left: +scrollDistance,
behavior: "smooth",
});
activeIndex = 0;
updateIndicators(activeIndex);
} else {
slider.scrollBy({
top: 0,
left: +scrollDistance,
behavior: "smooth",
});
activeIndex = (activeIndex + 1) % 3;
console.log(activeIndex);
updateIndicators(activeIndex);
}
});






Hi,
a very nice slider! I want to use it in my online movie database. But I have not enough know-how in javascript. How I can change the description nodes of the “movie0” Element (expanding the array is not the problem)? Shoud I use a other element type for that?
An other problem is, that I need to embed the whole slider in a div instead of an document. I get not the right positions of the nav buttons and the font type is not displayed.
I have no idea…
Sincerly,
Ulli