Carousel

A carousel with motion and swipe built using Embla.

1
2
3
4
5

Installation

npx @kosori/cli add components carousel

Usage

import {
  Carousel,
  CarouselContent,
  CarouselItem,
  CarouselNext,
  CarouselPrevious,
} from '~/components/ui/carousel';
<Carousel>
  <CarouselContent>
    <CarouselItem>...</CarouselItem>
    <CarouselItem>...</CarouselItem>
    <CarouselItem>...</CarouselItem>
  </CarouselContent>
  <CarouselPrevious />
  <CarouselNext />
</Carousel>

Examples

Sizes

1
2
3
4
5

Simple

To set the size of the items, you can use the basis utility class on the <CarouselItem />.

// 33% of the carousel width.
<Carousel>
  <CarouselContent>

    <CarouselItem className='basis-1/3'>...</CarouselItem>
    <CarouselItem className='basis-1/3'>...</CarouselItem>
    <CarouselItem className='basis-1/3'>...</CarouselItem>
  </CarouselContent>
</Carousel>

Responsive

// 50% on small screens and 33% on larger screens.
<Carousel>

  <CarouselContent>

    <CarouselItem className='md:basis-1/2 lg:basis-1/3'>...</CarouselItem>
    <CarouselItem className='md:basis-1/2 lg:basis-1/3'>...</CarouselItem>
    <CarouselItem className='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?

We 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. We found pl-[VALUE] and -ml-[VALUE] utilities much easier to use. You can always adjust this in your own project if you need to.

1
2
3
4
5

Simple

<Carousel>

  <CarouselContent className='-ml-4'>

    <CarouselItem className='pl-4'>...</CarouselItem>
    <CarouselItem className='pl-4'>...</CarouselItem>
    <CarouselItem className='pl-4'>...</CarouselItem>
  </CarouselContent>
</Carousel>

Responsive

<Carousel>

  <CarouselContent className='-ml-2 md:-ml-4'>
    <CarouselItem className='pl-2 md:pl-4'>...</CarouselItem>
    <CarouselItem className='pl-2 md:pl-4'>...</CarouselItem>
    <CarouselItem className='pl-2 md:pl-4'>...</CarouselItem>
  </CarouselContent>
</Carousel>

Orientation

Use the orientation prop to set the orientation of the carousel.

1
2
3
4
5

<Carousel orientation='vertical | horizontal'>
  <CarouselContent>
    <CarouselItem>...</CarouselItem>
    <CarouselItem>...</CarouselItem>
    <CarouselItem>...</CarouselItem>
  </CarouselContent>
</Carousel>

Options

You can pass options to the carousel using the opts prop. See the Embla Carousel docs for more information.

<Carousel

  opts={{
    align: 'start',
    loop: true,
  }}
>
  <CarouselContent>
    <CarouselItem>...</CarouselItem>
    <CarouselItem>...</CarouselItem>
    <CarouselItem>...</CarouselItem>
  </CarouselContent>
</Carousel>

API

Use a state and the setApi props to get an instance of the carousel API.

1
2
3
4
5
Slide 0 of 0
import { useEffect, useState } from 'react';
 
import type { CarouselApi } from '@kosori/ui/carousel'; 
 
export const Example = () => {
  const [api, setApi] = useState<CarouselApi>(); 
  const [current, setCurrent] = useState(0);
  const [count, setCount] = useState(0);
 
  useEffect(() => {
    if (!api) {
      return;
    }
 
    setCount(api.scrollSnapList().length);
    setCurrent(api.selectedScrollSnap() + 1);
 
    api.on('select', () => {
      setCurrent(api.selectedScrollSnap() + 1);
    });
  }, [api]);
 
  return (

    <Carousel setApi={setApi}>
      <CarouselContent>
        <CarouselItem>...</CarouselItem>
        <CarouselItem>...</CarouselItem>
        <CarouselItem>...</CarouselItem>
      </CarouselContent>
    </Carousel>
  );
};

Events

You can listen to events using the api instance from setApi.

import { useEffect, useState } from 'react';
 
import type { CarouselApi } from '@kosori/ui/carousel'; 
 
export const Example = () => {
  const [api, setApi] = useState<CarouselApi>(); 
 

  useEffect(() => {
    if (!api) {
      return;
    }
 
    api.on('select', () => {
      // Do something on select.
    });
  }, [api]);
 
  return (

    <Carousel setApi={setApi}>
      <CarouselContent>
        <CarouselItem>...</CarouselItem>
        <CarouselItem>...</CarouselItem>
        <CarouselItem>...</CarouselItem>
      </CarouselContent>
    </Carousel>
  );
};

See the Embla Carousel docs for more information on using events.

Plugins

You can use the plugins prop to add plugins to the carousel.

import Autoplay from 'embla-carousel-autoplay'; 
 
export const Example = () => {
  return (
    <Carousel

      plugins={[
        Autoplay({
          delay: 2000,
        }),
      ]}
    >
      // ...
    </Carousel>
  );
};
1
2
3
4
5

See the Embla Carousel docs for more information on using events.

On this page