Carousel
A carousel with motion and swipe built using Embla.
Source code
Click here to see the source code for this component on GitHub. Feel free to copy it and adjust it for your own use.
About
The carousel component is built using the Embla Carousel library.
Installation
npx ui-thing@latest add carousel
Usage
<template>
<UiCarousel>
<UiCarouselContent>
<UiCarouselItem>...</UiCarouselItem>
<UiCarouselItem>...</UiCarouselItem>
<UiCarouselItem>...</UiCarouselItem>
</UiCarouselContent>
<UiCarouselPrevious />
<UiCarouselNext />
</UiCarousel>
</template>
Examples
Sizes
To set the size of the items, you can use the basis
utility class on the <UiCarouselItem />
.
Other Size Example
<template>
<!-- 33% of the carousel width. -->
<UiCarousel>
<UiCarouselContent>
<UiCarouselItem class="basis-1/3">...</UiCarouselItem>
<UiCarouselItem class="basis-1/3">...</UiCarouselItem>
<UiCarouselItem class="basis-1/3">...</UiCarouselItem>
</UiCarouselContent>
</UiCarousel>
</template>
Responsive
<template>
<!-- 50% on small screens and 33% on larger screens. -->
<UiCarousel>
<UiCarouselContent>
<UiCarouselItem class="md:basis-1/2 lg:basis-1/3">...</UiCarouselItem>
<UiCarouselItem class="md:basis-1/2 lg:basis-1/3">...</UiCarouselItem>
<UiCarouselItem class="md:basis-1/2 lg:basis-1/3">...</UiCarouselItem>
</UiCarouselContent>
</UiCarousel>
</template>
Spacing
To set the spacing between the items, we use a pl-[VALUE]
utility on the <UiCarouselItem />
and a negative -ml-[VALUE]
on the <UiCarouselContent />
.
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.
Other Spacing Example
<template>
<UiCarousel>
<UiCarouselContent class="-ml-4">
<UiCarouselItem class="pl-4"> ... </UiCarouselItem>
<UiCarouselItem class="pl-4"> ... </UiCarouselItem>
<UiCarouselItem class="pl-4"> ... </UiCarouselItem>
</UiCarouselContent>
</UiCarousel>
</template>
Responsive
<template>
<UiCarousel>
<UiCarouselContent class="-ml-2 md:-ml-4">
<UiCarouselItem class="pl-2 md:pl-4"> ... </UiCarouselItem>
<UiCarouselItem class="pl-2 md:pl-4"> ... </UiCarouselItem>
<UiCarouselItem class="pl-2 md:pl-4"> ... </UiCarouselItem>
</UiCarouselContent>
</UiCarousel>
</template>
Orientation
Use the orientation
prop to set the orientation of the carousel.
Thumbnail
Options
You can pass options to the carousel using the opts
prop. See the Embla Carousel docs for more information.
<template>
<UiCarousel :opts="{ align: 'start', loop: true }">
<UiCarouselContent>
<UiCarouselItem>...</UiCarouselItem>
<UiCarouselItem>...</UiCarouselItem>
<UiCarouselItem>...</UiCarouselItem>
</UiCarouselContent>
</UiCarousel>
</template>
API
Method 1
Use the @init-api
emit method on <UiCarousel />
component to set the instance of the API.
Method 2
You can access it through setting a template ref on the <UiCarousel />
component.
<template>
<UiCarousel ref="carouselContainerRef"> ... </UiCarousel>
</template>
<script setup lang="ts">
import { UiCarousel } from "#components";
const carouselContainerRef = ref<InstanceType<typeof UiCarousel> | null>(null);
function accessApi() {
carouselContainerRef.value?.carouselApi.on("select", () => {});
}
</script>
Events
You can listen to events using the API. To get the API instance use the @init-api
emit method on the <UiCarousel />
component
<template>
<UiCarousel @init-api="setApi"> ... </UiCarousel>
</template>
<script setup lang="ts">
import type { CarouselApi } from "~/utils/useCarousel";
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>
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 <UiCarousel v-slot="slotProps" />
component to extend the functionality.
<template>
<UiCarousel v-slot="{ canScrollNext, canScrollPrev }">
...
<UiCarouselPrevious v-if="canScrollPrev" />
<UiCarouselNext v-if="canScrollNext" />
</UiCarousel>
</template>
Plugins
You can use the plugins
prop to add plugins to the carousel.
npm i embla-carousel-autoplay
<template>
<UiCarousel class="w-full max-w-xs" :plugins="[Autoplay({ delay: 2000 })]"> ... </UiCarousel>
</template>
<script setup lang="ts">
import Autoplay from "embla-carousel-autoplay";
</script>
See the Embla Carousel docs for more information on using plugins.