Carousel
A carousel with motion and swipe built using Embla.
About
The carousel component is built using the Embla Carousel library.
Installation
npx shadcn-vue@latest add carousel
Usage
<script setup lang="ts">
import {
Carousel,
CarouselContent,
CarouselItem,
CarouselNext,
CarouselPrevious,
} from '@/components/ui/carousel'
</script>
<template>
<Carousel>
<CarouselContent>
<CarouselItem>...</CarouselItem>
<CarouselItem>...</CarouselItem>
<CarouselItem>...</CarouselItem>
</CarouselContent>
<CarouselPrevious />
<CarouselNext />
</Carousel>
</template>
Examples
Sizes
To set the size of the items, you can use the basis
utility class on the <CarouselItem />
.
Example
// 33% of the carousel width.
<Carousel>
<CarouselContent>
<CarouselItem class="basis-1/3">...</CarouselItem>
<CarouselItem class="basis-1/3">...</CarouselItem>
<CarouselItem class="basis-1/3">...</CarouselItem>
</CarouselContent>
</Carousel>
Responsive
// 50% on small screens and 33% on larger screens.
<Carousel>
<CarouselContent>
<CarouselItem class="md:basis-1/2 lg:basis-1/3">...</CarouselItem>
<CarouselItem class="md:basis-1/2 lg:basis-1/3">...</CarouselItem>
<CarouselItem class="md:basis-1/2 lg:basis-1/3">...</CarouselItem>
</CarouselContent>
</Carousel>
Spacing
To set the spacing between the items, we use a pl-[VALUE]
utility on the <CarouselItem />
and a negative -ml-[VALUE]
on the <CarouselContent />
.
Why: I tried to use the gap
property or a grid
layout on the CarouselContent
but it required a lot of math and mental effort to get the spacing right. I found pl-[VALUE]
and -ml-[VALUE]
utilities much easier to use.
You can always adjust this in your own project if you need to.
Example
<template>
<Carousel>
<CarouselContent class="-ml-4">
<CarouselItem class="pl-4">
...
</CarouselItem>
<CarouselItem class="pl-4">
...
</CarouselItem>
<CarouselItem class="pl-4">
...
</CarouselItem>
</CarouselContent>
</Carousel>
</template>
Responsive
<template>
<Carousel>
<CarouselContent class="-ml-2 md:-ml-4">
<CarouselItem class="pl-2 md:pl-4">
...
</CarouselItem>
<CarouselItem class="pl-2 md:pl-4">
...
</CarouselItem>
<CarouselItem class="pl-2 md:pl-4">
...
</CarouselItem>
</CarouselContent>
</Carousel>
</template>
Orientation
Use the orientation
prop to set the orientation of the carousel.
<Carousel orientation="vertical | horizontal">
...
</Carousel>
Thumbnails
Options
You can pass options to the carousel using the opts
prop. See the Embla Carousel docs for more information.
<template>
<Carousel
:opts="{
align: 'start',
loop: true,
}"
>
<CarouselContent>
<CarouselItem>...</CarouselItem>
<CarouselItem>...</CarouselItem>
<CarouselItem>...</CarouselItem>
</CarouselContent>
</Carousel>
</template>
API
Method 1
Use the @init-api
emit method on <Carousel />
component to set the instance of the API.
Method 2
You can access it through setting a template ref on the <Carousel />
component.
<script setup>
const carouselContainerRef = ref<InstanceType<typeof Carousel> | null>(null)
function accessApi() {
carouselContainerRef.value?.carouselApi.on('select', () => {})
}
</script>
<template>
<Carousel ref="carouselContainerRef">
...
</Carousel>
</template>
Events
You can listen to events using the API. To get the API instance use the @init-api
emit method on the <Carousel />
component
<script setup>
import { nextTick, ref, watch } from 'vue'
import { useCarousel } from '@/components/ui/carousel'
const api = ref<CarouselApi>()
function setApi(val: CarouselApi) {
api.value = val
}
const stop = watch(api, (api) => {
if (!api)
return
// Watch only once or use watchOnce() in @vueuse/core
nextTick(() => stop())
api.on('select', () => {
// Do something on select.
})
})
</script>
<template>
<Carousel @init-api="setApi">
...
</Carousel>
</template>
See the Embla Carousel docs for more information on using events.
Slot Props
You can get the reactive slot props like carouselRef, canScrollNext..Prev, scrollNext..Prev
using the v-slot
directive in the <Carousel v-slot="slotProps" />
component to extend the functionality.
<template>
<Carousel v-slot="{ canScrollNext, canScrollPrev }">
...
<CarouselPrevious v-if="canScrollPrev" />
<CarouselNext v-if="canScrollNext" />
</Carousel>
</template>
Plugins
You can use the plugins
prop to add plugins to the carousel.
npm i embla-carousel-autoplay
<script setup lang="ts">
import Autoplay from 'embla-carousel-autoplay'
</script>
<template>
<Carousel
class="w-full max-w-xs"
:plugins="[Autoplay({
delay: 2000,
})]"
>
...
</Carousel>
</template>
See the Embla Carousel docs for more information on using plugins.