Building an image carousel with Vue.js
Tags: vue, javascript, carousel
Published: 2018-02-28 19:38:10

---
title: Building an image carousel with Vue.js
published: true
description: Building an image carousel with Vue.js
tags: vue, javascript, carousel
cover_image: https://thepracticaldev.s3.amazonaws.com/i/2g4cijab65jroh4lwndq.png
---

In my few years of experience as a web developer I have used more than a dozen carousel plugins, some of them were really good and some of them were rather clunky. 

Recently I wanted to use a small image carousel(for a personal project of mine) that would cover the upper part of a card. The carousel should have arrows and thumbnails to navigate through the images and the thumbnails should be on the bottom of the carousel. 

I was tempted to use something like owl-carousel and get on with my day, but I also kind of wanted to build something new with Vue, which I have been learning for a few months now. 

Since I had plenty of time I fired up my favorite IDE and started a new project.

For this project I used [Bulma](https://bulma.io/) (a CSS framework based on Flexbox) and of course [Vue.js](https://vuejs.org/). If you are new to Vue I encourage you to read [my first post](https://dev.to/tsanak/make-your-life-easier-with-vuejs-4mj5) and the awesome [documentation](https://vuejs.org/v2/guide/).

###Sneak peek
![alt text](https://thepracticaldev.s3.amazonaws.com/i/lqd5gxqbkwkmoj02dfvi.gif "Small image carousel with Vue")

###Let’s get technical
HTML skeleton of the project
```html
<section class="section" id="app">
    <div class="columns">
        <div class="column is-4">
            <div class="card">
                <div class="card-content">
                    <div class="card-carousel">
                        <div class="card-img">
                            <img src="/some-image.jpg" alt="Some image">
                            <div class="actions">
                                <span class="prev">
                                    <i class="fas fa-chevron-left"></i>
                                </span>
                                <span class="next">
                                    <i class="fas fa-chevron-right"></i>
                                </span>
                            </div>
                        </div>
                        <div class="thumbnails">
                            <div class="thumbnail-img">
                                <img src="/some-thumbnail.jpg" alt="Some thumbnail">
                            </div>
                            <div class="thumbnail-img active">
                                <img src="/some-thumbnail.jpg" alt="Some thumbnail">
                            </div>
                            <div class="thumbnail-img">
                                <img src="/some-thumbnail.jpg" alt="Some thumbnail">
                            </div>
                        </div>
                    </div>
                    <p>Card description.</p>
                </div>
            </div>
        </div>
    </div>
</section>
```
After a little CSS it ended up looking like this:
![alt text](https://thepracticaldev.s3.amazonaws.com/i/rlrtp2zzunh2hh7sh3xr.png
 "Carousel skeleton")

Now that we got the styling out of the way, we can focus on the functionality 🤖
```html
<div class="card-carousel">
    <div class="card-img">
        <img :src="currentImage" alt="">
        <div class="actions">
            <span @click="prevImage" class="prev">
                <i class="fas fa-chevron-left"></i>
            </span>
            <span @click="nextImage" class="next">
                <i class="fas fa-chevron-right"></i>
            </span>
        </div>
    </div>
    <div class="thumbnails">
        <div 
            v-for="(image, index) in  images"
            :key="image.id"
            :class="['thumbnail-image', (activeImage == index) ? 'active' : '']"
            @click="activateImage(index)"
        >
            <img :src="image.thumb">
        </div>
    </div>
</div>
```
A short explanation
```html
<!-- 
    Bind the source of the image to a variable,
    so when the variable changes, so does the photo
-->
<img :src="currentImage" alt="">
<!-- 
    Loop through the images array,
    @click="activateImage(index)" on click call the function activateImage 
    :class="['thumbnail-image', (activeImage == index) ? 'active' : '']"
    bind the class of the div to an array. Always show 'thumbnail-image' class 
    and show the class 'active' only for the image that is currently active
-->
<div 
    v-for="(image, index) in  images"
    :key="image.id"
    :class="['thumbnail-image', (activeImage == index) ? 'active' : '']"
    @click="activateImage(index)"
>
    <img :src="image.thumb">
</div>
```

and all the JS code that was needed: 
```javascript
    var app = new Vue({
        el: '#app',
        data() {
            return {
                //Array to hold all carousel images
                images: [
                    {
                        id: '1',
                        big: 'images/p1.jpeg',
                        thumb: 'images/thumbs/p1.jpeg'
                    },
                    {
                        id: '2',
                        big: 'images/p2.jpeg',
                        thumb: 'images/thumbs/p2.jpeg'
                    },
                    {
                        id: '3',
                        big: 'images/p3.jpeg',
                        thumb: 'images/thumbs/p3.jpeg'
                    },
                    {
                        id: '4',
                        big: 'images/p4.jpeg',
                        thumb: 'images/thumbs/p4.jpeg'
                    }
                ],
                //Index of the active image on the images array
                activeImage: 0
            }
        },
        computed: {
            // currentImage gets called whenever activeImage changes
            // and is the reason why we don't have to worry about the 
            // big image getting updated
            currentImage() {
                return this.images[this.activeImage].big;
            }
        },
        methods: {
            // Go forward on the images array 
            // or go at the first image if you can't go forward :/ 
            nextImage() {
                var active = this.activeImage + 1;
                if(active >= this.images.length) {
                    active = 0;
                }
                this.activateImage(active);
            },
            // Go backwards on the images array 
            // or go at the last image
            prevImage() {
                var active = this.activeImage - 1;
                if(active < 0) {
                    active = this.images.length - 1;
                }
                this.activateImage(active);
            },
            activateImage(imageIndex) {
                this.activeImage = imageIndex;
            }
        }
    });
```

Here is the finished project (again 😅)
![alt text](https://thepracticaldev.s3.amazonaws.com/i/lqd5gxqbkwkmoj02dfvi.gif "Small image carousel with Vue")

🎉Thank you for reading through all this and I hope you found something helpful🎉



You can find all the code on [github](https://github.com/tsanak/vue-carousel)

All the photos were taken from Pexels.com
https://www.pexels.com/photo/bang-blast-celebration-color-287487/
https://www.pexels.com/photo/person-hands-squash-fruit-112352/
https://www.pexels.com/photo/action-blur-car-daylight-246320/
https://www.pexels.com/photo/auto-automobile-blur-bokeh-242276/