JavaScript Image Slider [ How To Build One ]

Warren Davies Avatar

Follow on Twitter

How can you make a JavaScript image slider from the scratch? How do JavaScript image slideshows really work? Do we really need JavaScript for carousels nowadays? CSS has come a long way, and it’s actually possible to make a pretty decent slider with pure CSS.

However, you’re still very limited in what you can do with CSS alone, so if you want something more complex, you’ll need to build your image slider using JavaScript.

But then your next question becomes, how to build one? Well fear not my friend, because by the end of this post you’ll know how to build an image slider in JavaScript -source code provided!-, including navigation buttons and breadcrumbs.

Let’s do it!

Create the Structure for The Image Slider with HTML

First, we’ll have to create the basic structure for the image slider. The html for our image slider will look like this:

<div class="container">
  <div class="slider">
    <div class="slider__slides">
      <div class="slider__slide active"></div>
      <div class="slider__slide"></div>
      <div class="slider__slide"></div>
      <div class="slider__slide"></div>
    </div>
  </div>
</div>
Code language: HTML, XML (xml)

So, container is just the element that contains the future JavaScript images slideshow. This can be absolutely any part of your site, but I’ve just gone for a simple flexbox:

.container {
    display: flex;
    align-items: center;
    justify-content: center;
}
Code language: CSS (css)

Next is the main slider element. This will hold the image slides and the navigation elements:

.slider {
    display: block;
    position: relative;
    width: 100%;
    max-width: 900px;
    margin: 10px;
    background-color: white;
    overflow: hidden;
}
Code language: CSS (css)

You can adjust the size in any way that floats your boat – just make sure there’s a position property applied to it.

We also have a container div for the slides, slider__slides and four slider__slide elements, which I’ve styled like this:


.slider__slides {
  width: 100%;
  padding-top: 66%;
}

.slider__slide {
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 50px;
    font-weight: bold;   
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background-color: lemonchiffon;
    transition: 1s;
    opacity: 0;
}

.slider__slide.active {
    opacity: 1;
}

Code language: CSS (css)

Now, here’s where it gets a little interesting. Setting padding-top to a percentage in slider__slides will maintain its aspect ratio.

The the slides themselves are positioned absolutely, top and left are both 0, while width and height are both 100%.

This means that each slide will completely fill the first parent element that has a position property applied to it (that’s why I said make sure you do that to the slider element).

This also means that the four slides are stacked directly on top of each other. Notice that I’ve set the opacity of each slide to 0 – this makes them transparent. But the .slider__slide.active part means that any element which has both the slider__slide and active classes will have an opacity of 1 – making the active slide visible.

Here’s what that gives us:

As expected, we can only see slide 1 at the moment, with its pale yellow (lemonchiffon, to be precise) background. Now let’s add the images…

Putting Images into the JavaScript Image Slideshows

There are a few ways to make an image slider in JavaScript.

One is to add the images using the css background property, and have a separate class for each image. Another way is to have just have one slide, and change it’s background image directly with JS.

However, the approach we’ll take here is to use an img element inside each slide, like this:

  <div class="slider__slide active">
     <img src="https://upload.wikimedia.org/wikipedia/commons/thumb/5/56/Shakuzoji_Kuginuki_Jizo-3586.jpg/800px-Shakuzoji_Kuginuki_Jizo-3586.jpg" alt="A rooftop in Japan" />
  </div>
Code language: HTML, XML (xml)

I’ve added one image for each slide, but we can still only see the first image, the one with the active class:

So now let’s add the navigation elements so people can cycle through the images on the slider.

Add Forwards and Backwards Buttons to the JavaScript Image Slider

Users look for navigation buttons at the far left and right edges of sliders – so that’s where we’ll put them!

First let’s add these elements to the markup, inside slider, but below slider__slides:

<div class="container">
  <div class="slider">
    <div class="slider__slides">
      <!-- our slides go here -->
    </div>
    <div id="nav-button--prev" class="slider__nav-button"></div>
    <div id="nav-button--next" class="slider__nav-button"></div>
  </div>
</div>
Code language: HTML, XML (xml)

As well as the slider__nav-button class, each button has a unique id – as we’re making our image slider using JavaScript, we’ll need these IDs so that we can select these elements within our JS code.

You can style your buttons however you want, of course. Personally, I’m just gonna keep it simple with a grey box. Hey – sometimes the simple option is the best:

.slider__nav-button {
    position: absolute;
    height: 70px;
    width: 70px;
    background-color: #333;
    opacity: .8;
    cursor: pointer;
}
Code language: CSS (css)

I’ve set opacity to .8, so the buttons will be a little transparent and won’t fully block whatever is behind them. And since we want these to be clickable we need cursor: pointer so that the user knows they can click it.

Now, because these two buttons are at different sides of the slider, we’ll need to use slightly different CSS to position each one. We can use the ids for that:

#nav-button--prev {
    top: 50%;
    left: 0;
    transform: translateY(-50%);
}

#nav-button--next {
    top: 50%;
    right: 0;
    transform: translateY(-50%);
}
Code language: CSS (css)

Setting top to 50% will put the top of the element halfway down the parent. So it won’t be perfectly centered vertically – it’ll be a little lower than it should be.

The solution is to also add transform: translateY(-50%);. When you translate by a percentage, you move the element by a proportion of its own size. So -50% will perfectly center the button, not matter what its height happens to be. Pretty nice trick!

Adding Arrows To The Navigation Buttons With CSS

At the moment our navigation buttons are just grey boxes – we should indicate that these are buttons somehow. There are loads of ways of doing this – you could use an image of an arrow, an SVG, or even just write “Prev” and “Next”. But here’s another way:

#nav-button--prev::after,
#nav-button--next::after {
    content: "";
    position: absolute;
    border: solid white;
    border-width: 0 4px 4px 0;
    display: inline-block;
    padding: 3px;
    width: 40%;
    height: 40%;
}
Code language: CSS (css)

This uses the after pseudoelement, which means we can add it to the JavaScript images slideshow without having to add anymore html. It creates a box with a solid white border along only its right and bottom edges.

All we need to do now, is rotate the boxes so that the borders look like arrows, and use ‘translate’ to make sure they’re centred within the button:

#nav-button--next::after{
    top: 50%;
    right: 50%;
    transform: translate(25%, -50%) rotate(-45deg);
}

#nav-button--prev::after {
    top: 50%;
    right: 50%;
    transform: translate(75%, -50%) rotate(135deg);
}
Code language: CSS (css)

And let’s also add a media query to shrink these buttons a bit on smaller screens:

@media screen and (max-width: 640px) {
  .slider__nav-button {
    height: 40px;
    width: 40px;
  }
}
Code language: CSS (css)

If we put all this togther, here’s what we get:

Okay, it’s starting to look like a slider! Moving on…

Add Breadcrumbs To The JavaScript Images Slideshow

Breadcrumbs (or navigation dots, bullets or whatever else you want to call them) are actually pretty easy to add. First let’s update our HTML once again:

<div class="container">
  <div class="slider">
    <div class="slider__slides">
      <!-- our slides go here -->
    </div>
    <div id="nav-button--prev" class="slider__nav-button"></div>
    <div id="nav-button--next" class="slider__nav-button"></div>
    <div class="slider__nav">
      <div class="slider__navlink active"></div>
      <div class="slider__navlink"></div>
      <div class="slider__navlink"></div>
      <div class="slider__navlink"></div>
    </div>
  </div>
  </div>
</div>
Code language: HTML, XML (xml)

Now we have a slider__nav element, which contains four slider__navlink divs – one for each slide. The first one has an active class added to it also, which we can use to make the active breadcrumb stand out from the rest.

Traditionally, breadcrumbs like these go at the bottom of a slider:

.slider__nav {
    position: absolute;
    bottom: 3%;
    left: 50%;
    transform: translateX(-50%);
    text-align: center;
}
Code language: CSS (css)

We’ve put the container for the breadcrumbs 3% away from the bottom of the image slider, and used the same centering trick we used with the buttons, only this time horizontally. Now for the breadcrumbs themselves:

.slider__navlink {
    display: inline-block;
    height: 20px;
    width: 20px;
    border-radius: 50%;
    border: 1px #fff solid;
    background-color: #333;
    opacity: .8;
    margin: 0 10px 0 10px;
    cursor: pointer;
}

.slider__navlink.active {
    background-color: #fff;
    border: 1px #333 solid;
}
Code language: CSS (css)

Pretty simple stuff here – just using border-radius to make them circles, and setting the background colour to white on the active slide. The rest are filled in with the same grey used in the buttons.

Here’s what we get:

We’re almost there – we just need to make these buttons actually do something! We’ll be using JavaScript for that.

Putting the JavaScript into the Image Slideshows

First, let’s make it easy to deal with our slides and breadcrumbs using JS:

let slides = document.getElementsByClassName("slider__slide");
let navlinks = document.getElementsByClassName("slider__navlink");
Code language: JavaScript (javascript)

The first line goes through our markup, finds every element called slider__slide, and stores a pointer to it in an array called slides. The next line does the same for our breadcrumb elements, this time putting them in an array called navlinks.

We also need to keep track of which slide is currently active, so lets make a variable for that:

let currentSlide = 0;
Code language: JavaScript (javascript)

I’ve set this to 0 because as you may know, in JavaScript arrays are indexed from 0, not 1. So our first slide is in slides[0], the second is in slides[1], and so on.

Now we need to add event listeners to each of our buttons:

document.getElementById("nav-button--next").addEventListener("click", () => {
    changeSlide(currentSlide + 1)
});
document.getElementById("nav-button--prev").addEventListener("click", () => {
    changeSlide(currentSlide - 1)
});
Code language: JavaScript (javascript)

When a user clicks one of these buttons, our image slider JavaScript source code will call a function called changeSlide (which we’ll create in a minute), and pass an argument – currentSlide + 1 for the forwards button, and currentSlide - 1 for the backwards one. That lets us know which slide the user is trying to move to, so we can put the active class onto that slide, and take it off of the current slide.

As you can see here, I’ve wrapped the function call within an anonymous function – this is necessary when you want to pass an argument using an event listener. For example, this doesn’t work:

document.getElementById("nav-button--next").addEventListener("click", changeSlide(currentSlide + 1));
Code language: JavaScript (javascript)

So that’s why you have to put the function call within the () => { } block.

Creating the JavaScript Function That Will Change The Slide

Here’s what the changeSlide() function looks like:

function changeSlide(moveTo) {
    if (moveTo >= slides.length) {moveTo = 0;}
    if (moveTo < 0) {moveTo = slides.length - 1;}
    
    slides[currentSlide].classList.toggle("active");
    navlinks[currentSlide].classList.toggle("active");
    slides[moveTo].classList.toggle("active");
    navlinks[moveTo].classList.toggle("active");
    
    currentSlide = moveTo;
}
Code language: JavaScript (javascript)

Let’s break this down step-by-step:

  1. changeSlide takes one argument, moveTo, which is the number of the slide you want to change to.
  2. The first line checks if moveTo is equal to or greater than slides.length – that would mean we’re on the final slide, and trying to move forward. In this case, we’ll set moveTo to 0 – which will take us back to the first slide.
  3. The next line does the same if the user tries to go backwards from the first slide – we’ll just loop them to the final slide
  4. The next four lines use the slides and navlinks arrays we created earlier. By using classList.toggle("active"), our code will remove the active class from the current slide, and add it to the one we’re trying to move to.
  5. Finally, we set currentSlide to equal moveTo, since that’s the active slide now.

As you might remember from earlier, we added transition: 1s to our slider__slides element. This means that the change in opacity that is triggered when we add or remove the active class take 1 second to complete – giving a nice fade-in effect.

But before we look at the end result there’s just one more thing we need to do…

Making The Breadcrumbs Clickable

Picture of Columbo advising you to make your breadcrumbs clickable

Ever tried to click something, that you thought was clickable, but it turned out not to be clickable? Remember that feeling of disappointment that swelled up in your gut? Let’s not do that to our users! Let’s make it easy for them to jump from one slide to another by clicking the breadcrumbs:

document.querySelectorAll('.slider__navlink').forEach((bullet, bulletIndex) => {
    bullet.addEventListener('click', () => {
        if (currentSlide !== bulletIndex) {
            changeSlide(bulletIndex);
        }
    })
})
Code language: JavaScript (javascript)

Here we’ve used querySelectorAll to grab all of the slider__navlink elements, and then we’re using forEach to loop through them.

So on the first loop, bullet will point to the first slide, and bulletIndex will equal 0.
On the next loop, bullet will point to the second slide, and bulletIndex will equals 1.
And so on.

The idea is, if they click a button, we know they want to change to slide bulletIndex – so we can just pass that value to our funtion with changeSlide(bulletIndex).

However, we’d better first check if they are already on slide bulletIndex. There’s no point fading out and then back in to the same slide. So the if statement ensures we’ll only call changeSlide, if currentSlide does not equal bulletIndex.

The Final Product

OK we’re done! Below you can see what we ended up with.

Can you guess which famous video game series these images are a tip of the hat to?

  • 100 points if you can guess just from the first image
  • 75 points if you guess on the second image
  • 30 points if you get it on the third image
  • 10 points if you need all four images to figure it out
  • 0 points if you don’t know

Of course, we’ve only scractched the surface of what’s possible when creating an image slider using JavaScript. You have a good framework here that you can experiment with. You can change the shape, style, and position of these elements however you need, and of course, you can play around with different transitions when moving between slides.

But if you want to make something that’s not only visually slick but super-performant too, why reinvent the wheel? Take a look at fullPage.js and see if it’s the tool for you.

As the name implies fullPage.js helps you create fullscreen scrolling websites. You get a range of different effects that will impress your visitors, it’s really easy to set up, and it works with other frameworks and CMSs including React and WordPress.

Check it out!

Was this page helpful?