Introduction
A website's carousel or slider is an effective way to display multiple images or content in a single space. It encourages visitors to concentrate on important website content while also improving overall visual appeal by saving screen space.
In this article, we will learn how to create a draggable carousel from scratch using vanilla JavaScript. This will be very detailed and explanatory so that everyone can understand it.
Note: The source code is available on GitHub.
Getting Started
To build the draggable carousel from scratch in vanilla JavaScript, we'd need to use a set of unique mouse events, such as:
mousedown
: When a mouse button is pressed while the pointer is inside an element, themousedown
event is triggered.mouseenter
: When a mouse is first moved into an element, themouseenter
event is triggered.mouseleave
: When the cursor of a mouse moves out of an element, themouseleave
event is triggered (this is the opposite ofmouseenter
).mouseup
: Themouseup
event is triggered when the pointer is within the element and a button on a mouse is released.mousemove
: When a mouse is moved while the cursor is inside it, themousemove
event is triggered.
Let's begin by creating our HTML file; basically, we'd have as many cards as we want with whatever content we want. To avoid pasting HTML code of more than 80 lines, I'd remove the content from the cards and rather make use of boxes:
<div class="slider-container">
<div class="inner-slider">
<div class="card"></div>
<div class="card"></div>
<div class="card"></div>
<div class="card"></div>
<div class="card"></div>
<div class="card"></div>
<div class="card"></div>
</div>
</div>
Let’s also add some basic styles to the slider-container
, inner-slider
and the card
:
.card {
height: 300px;
width: 400px;
border-radius: 5px;
}
.card:nth-child(odd) {
background-color: blue;
}
.card:nth-child(even) {
background-color: rgb(0, 183, 255);
}
.slider-container {
width: 80%;
height: 350px;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
overflow: hidden;
}
.inner-slider {
width: 150%;
display: flex;
gap: 10px;
pointer-events: none;
position: absolute;
top: 0;
left: 0;
}
Note: overflow: hidden;
was added to slider-container
, so it hides the other cards that are outside the specified width
. We also used position: absolute;
alongside top
and left
in the inner-slider
, so we can make use of the left
position later with JavaScript.
At this point, your page should look like this:
Making the Carousel Draggable
The first step will be to select the slider element, the slider itself, and the slider container. Then we'll set up three variables that we'll use later.
let sliderContainer = document.querySelector('.slider-container');
let innerSlider = document.querySelector('.inner-slider');
let pressed = false;
let startX;
let x;
As previously stated, we will use a large number of mouse eventListeners
to handle various operations. We will mostly be attaching them to the parent slider element.
The first event we'll watch for is the mousedown event, which is similar to but not exactly the same as a click. This is where we'll specify what we want to happen when a user clicks around the slider container.
Note: This differs from the click
event in that the click
event is fired after a full click action has occurred; that is, the mouse button is pressed and released while the pointer remains inside the same element. While, the mousedown
is executed the moment the button is pressed for the first time.
sliderContainer.addEventListener('mousedown', () => {
...
})
To demonstrate that the pressed
variable, which we previously initialized as false
, is pressed, we will first assign true
to it. We'll also set the startx
value to the offset value in the x
direction minus the innerSlider
offset value to the left
, which is currently 0
. We can see what this means by attempting to log out the value of startx
.
We'll also style the cursor
for better interaction. This is going to be set to grabbing
(to check what this does, try clicking within the slidercontainer
).
sliderContainer.addEventListener("mousedown", (e) => {
pressed = true;
startX = e.offsetX - innerSlider.offsetLeft;
sliderContainer.style.cursor = "grabbing";
});
Check out our hands-on, practical guide to learning Git, with best-practices, industry-accepted standards, and included cheat sheet. Stop Googling Git commands and actually learn it!
The next event we'd look for is mouseenter
; we're doing this to add basic interactivity by styling the cursor
to indicate that the slider or a specific slider card has been grabbed.
sliderContainer.addEventListener("mouseenter", () => {
sliderContainer.style.cursor = "grab";
});
After that, we would listen for the mouseup
event and set the cursor
style to grab
, so that when a user stops grabbing or clicking, the cursor
would change back to grab
rather than grabbing
. We'll also return the pressed
value to false
.
sliderContainer.addEventListener("mouseup", () => {
sliderContainer.style.cursor = "grab";
pressed = false;
});
We've been able to add some interactivity up to this point, but we haven't yet implemented the main functionality, a draggable carousel.
Handling the Core Logic
Let's now take care of the core logic; we'll still be targeting the sliderContainer
, but this time we'll be listening for a mousemove
event. In the call back function, we would check if pressed
is false
so that we could return the function, and it would do nothing.
sliderContainer.addEventListener("mousemove", (e) => {
if (!pressed) return;
...
});
But, if pressed
is true
, we can proceed to some other logics. The first step will be to prevent default behaviors, followed by setting x
to offsetX
(the x-coordinate of the mouse pointer relative to the container slider element).
sliderContainer.addEventListener("mousemove", (e) => {
if (!pressed) return;
e.preventDefault();
x = e.offsetX;
});
You'll notice that when we styled the innerSlider
CSS class, we added position: absolute
and a left
value of 0
. Now we're going to change the left
value to x-startX
dynamically when the user drags the carousel. (we are subtracting our current position from the offset of the parent div).
sliderContainer.addEventListener("mousemove", (e) => {
if (!pressed) return;
e.preventDefault();
x = e.offsetX;
innerSlider.style.left = `${x - startX}px`;
});
At this point, you'll notice that everything works fine because our slider now drags properly, but there's no limit to where the scroll can stop.
Let's take care of it now by defining a new function. The first thing will be to get the position of the inner and outer slider containers, then we can now create two conditional statements to work for both sides.
const checkBoundary = () => {
let outer = sliderContainer.getBoundingClientRect();
let inner = innerSlider.getBoundingClientRect();
if (parseInt(innerSlider.style.left) > 0) {
innerSlider.style.left = "0px";
}
if (inner.right < outer.right) {
innerSlider.style.left = `-${inner.width - outer.width}px`;
}
};
Once this is done, we can now call this function within the mousemove
event listener as the last thing:
sliderContainer.addEventListener("mousemove", (e) => {
...
checkBoundary();
});
We were able to successfully create a draggable slider with JavaScript from scratch using this method.
Conclusion
In this article, we have learned how to create a draggable carousel from scratch using vanilla JavaScript, we also learned the difference between all the mouse events used.