Carousel

Basic Info

A basic Vue carousel component. Useful for cycling through groups of images or text. Each template tag with prop v-slot:slide# becomes the content for a new slide in the carousel.

Props

Prop Type Description
slides Number Number of slides to cycle between
width String Width of the carousel. Accepts any standard CSS format (px, rem, %)
height String Height of the carousel. Accepts any standard CSS format (px, rem, %)

Example

<Carousel :slides="3" width="80%" height="300px">
  <template v-slot:slide1>
    <h2>Slide 1</h2>
  </template>

  <template v-slot:slide2>
    <h2>Slide 2</h2>
  </template>

  <template v-slot:slide3>
    <h2>Slide 3</h2>
  </template>
</Carousel>

Source

<template>
  <div class="carousel" v-bind:style="{ width: width, height: height }" >
    <div class="carousel-left center-vertical"><button class="carousel-button" @click="prevItem()"><font-awesome-icon class="icon" :icon="chevronLeft" /></button></div>
    <div class="carousel-center">
      <transition name="fade" mode="out-in">
        <div class="center" v-for="slide in slides" :key="`slide${slide}`" v-if="slideIndex==`${slide}`">
          <slot :name="`slide${slide}`"></slot>
        </div>
      </transition>
    </div>
    <div class="carousel-right center-vertical"><button class="carousel-button" @click="nextItem()"><font-awesome-icon class="icon" :icon="chevronRight" /></button></div>
  </div>
</template>

<script>
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'
import { faChevronLeft } from '@fortawesome/free-solid-svg-icons'
import { faChevronRight } from '@fortawesome/free-solid-svg-icons'

export default {
  name: 'Carousel',
  components: {FontAwesomeIcon},
  props: {
    width: String,
    height: String,
    slides: Number
  },
  data () {
    return {
      slideIndex: 1,
      chevronLeft: faChevronLeft,
      chevronRight: faChevronRight,
    }
  },
  methods: {
    nextItem: function() {
      if (this.slideIndex==this.slides) {
        this.slideIndex=1;
      } else {
        this.slideIndex++;
      }
    },
    prevItem: function() {
      if (this.slideIndex==1) {
        this.slideIndex=this.slides;
      } else {
        this.slideIndex--;
      }
    },
  }
}
</script>

<style lang="scss" scoped>
$border-color: #dee2e6;

h3 {
  margin-block-start: 0em;
}

.fade-enter-active, .fade-leave-active {
  transition: opacity .4s;
}
.fade-enter, .fade-leave-to {
  opacity: 0;
}

.carousel {
  border: 1px solid $border-color;
  border-radius: 4px;
  padding: 20px;
  display: flex;
  align-content: space-between;
}

.carousel-center {
  flex-grow: 1;
  margin-left: 10px;
  margin-right: 10px;
}

.center-vertical {
  display: flex;
  justify-content: space-between;
}

svg {
  display: block;
}

.carousel-button {
  background-color: white;
  border: 1px solid #ccc;
}

.icon {
  color: #ccc;
}
</style>