---
outline: deep
---

# Carousel

Carousels are used to cycle through a set of content slides in a horizontal scrollable area. Commonly used for image galleries, product showcases, and featured content. Powered by [Embla Carousel](https://www.embla-carousel.com/).

**`<l-carousel>`** — Custom Element · Shadow DOM

## Options

### Basic

Slides are `<l-carousel-item>` children. Set `--slide-size` and `--slide-gap` to control layout. Add `drag-free` for momentum scrolling.

```html
<l-carousel
  drag-free
  style="--slide-size: calc(100% / 3); --slide-gap: 1rem"
>
  <l-carousel-item>
    <div
      class="grid place-items-center w-full text-2xl bg-gray-300"
      style="height: 200px"
    >
      1
    </div>
  </l-carousel-item>
  <l-carousel-item>
    <div
      class="grid place-items-center w-full text-2xl bg-gray-300"
      style="height: 200px"
    >
      2
    </div>
  </l-carousel-item>
  <l-carousel-item>
    <div
      class="grid place-items-center w-full text-2xl bg-gray-300"
      style="height: 200px"
    >
      3
    </div>
  </l-carousel-item>
  <l-carousel-item>
    <div
      class="grid place-items-center w-full text-2xl bg-gray-300"
      style="height: 200px"
    >
      4
    </div>
  </l-carousel-item>
  <l-carousel-item>
    <div
      class="grid place-items-center w-full text-2xl bg-gray-300"
      style="height: 200px"
    >
      5
    </div>
  </l-carousel-item>
  <l-carousel-item>
    <div
      class="grid place-items-center w-full text-2xl bg-gray-300"
      style="height: 200px"
    >
      6
    </div>
  </l-carousel-item>
  <l-carousel-item>
    <div
      class="grid place-items-center w-full text-2xl bg-gray-300"
      style="height: 200px"
    >
      7
    </div>
  </l-carousel-item>
  <l-carousel-item>
    <div
      class="grid place-items-center w-full text-2xl bg-gray-300"
      style="height: 200px"
    >
      8
    </div>
  </l-carousel-item>
  <l-carousel-item>
    <div
      class="grid place-items-center w-full text-2xl bg-gray-300"
      style="height: 200px"
    >
      9
    </div>
  </l-carousel-item>
  <l-carousel-item>
    <div
      class="grid place-items-center w-full text-2xl bg-gray-300"
      style="height: 200px"
    >
      10
    </div>
  </l-carousel-item>
</l-carousel>
```

### Gallery

Add `single` for one slide at a time.

```html
<div class="p-8">
  <l-carousel
    class="w-[400px]"
    single
    style="--slide-size: 100%; --slide-gap: 0"
  >
    <l-carousel-item>
      <img
        class="object-cover"
        src="https://picsum.photos/id/10/1200/700"
        width="400"
        height="400"
        style="height: 400px; max-width: none"
      />
    </l-carousel-item>
    <l-carousel-item>
      <img
        class="object-cover"
        src="https://picsum.photos/id/11/1200/700"
        width="400"
        height="400"
        style="height: 400px; max-width: none"
      />
    </l-carousel-item>
    <l-carousel-item>
      <img
        class="object-cover"
        src="https://picsum.photos/id/12/1200/700"
        width="400"
        height="400"
        style="height: 400px; max-width: none"
      />
    </l-carousel-item>
  </l-carousel>
</div>
```

### Dots (bar)

Add `with-dots` for dot navigation. Default appearance is `bar`. Use `max-visible-dots` to cap the rendered dots — edge dots shrink when more dots exist beyond the window.

```html
<l-carousel
  single
  with-dots
  max-visible-dots="7"
>
  <l-carousel-item>
    <img
      class="object-cover w-full h-96"
      src="https://picsum.photos/id/17/1200/700"
      height="400"
    />
  </l-carousel-item>
  <l-carousel-item>
    <img
      class="object-cover w-full h-96"
      src="https://picsum.photos/id/18/1200/700"
      height="400"
    />
  </l-carousel-item>
  <l-carousel-item>
    <img
      class="object-cover w-full h-96"
      src="https://picsum.photos/id/19/1200/700"
      height="400"
    />
  </l-carousel-item>
  <l-carousel-item>
    <img
      class="object-cover w-full h-96"
      src="https://picsum.photos/id/20/1200/700"
      height="400"
    />
  </l-carousel-item>
  <l-carousel-item>
    <img
      class="object-cover w-full h-96"
      src="https://picsum.photos/id/21/1200/700"
      height="400"
    />
  </l-carousel-item>
  <l-carousel-item>
    <img
      class="object-cover w-full h-96"
      src="https://picsum.photos/id/22/1200/700"
      height="400"
    />
  </l-carousel-item>
  <l-carousel-item>
    <img
      class="object-cover w-full h-96"
      src="https://picsum.photos/id/23/1200/700"
      height="400"
    />
  </l-carousel-item>
  <l-carousel-item>
    <img
      class="object-cover w-full h-96"
      src="https://picsum.photos/id/24/1200/700"
      height="400"
    />
  </l-carousel-item>
  <l-carousel-item>
    <img
      class="object-cover w-full h-96"
      src="https://picsum.photos/id/25/1200/700"
      height="400"
    />
  </l-carousel-item>
  <l-carousel-item>
    <img
      class="object-cover w-full h-96"
      src="https://picsum.photos/id/26/1200/700"
      height="400"
    />
  </l-carousel-item>
  <l-carousel-item>
    <img
      class="object-cover w-full h-96"
      src="https://picsum.photos/id/27/1200/700"
      height="400"
    />
  </l-carousel-item>
  <l-carousel-item>
    <img
      class="object-cover w-full h-96"
      src="https://picsum.photos/id/28/1200/700"
      height="400"
    />
  </l-carousel-item>
</l-carousel>
```

### Dots (circle)

Set `dot-appearance="circle"` for circle dots.

```html
<l-carousel
  single
  with-dots
  dot-appearance="circle"
  max-visible-dots="7"
>
  <l-carousel-item>
    <img
      class="object-cover w-full h-96"
      src="https://picsum.photos/id/17/1200/700"
      height="400"
    />
  </l-carousel-item>
  <l-carousel-item>
    <img
      class="object-cover w-full h-96"
      src="https://picsum.photos/id/18/1200/700"
      height="400"
    />
  </l-carousel-item>
  <l-carousel-item>
    <img
      class="object-cover w-full h-96"
      src="https://picsum.photos/id/19/1200/700"
      height="400"
    />
  </l-carousel-item>
  <l-carousel-item>
    <img
      class="object-cover w-full h-96"
      src="https://picsum.photos/id/20/1200/700"
      height="400"
    />
  </l-carousel-item>
  <l-carousel-item>
    <img
      class="object-cover w-full h-96"
      src="https://picsum.photos/id/21/1200/700"
      height="400"
    />
  </l-carousel-item>
  <l-carousel-item>
    <img
      class="object-cover w-full h-96"
      src="https://picsum.photos/id/22/1200/700"
      height="400"
    />
  </l-carousel-item>
  <l-carousel-item>
    <img
      class="object-cover w-full h-96"
      src="https://picsum.photos/id/23/1200/700"
      height="400"
    />
  </l-carousel-item>
  <l-carousel-item>
    <img
      class="object-cover w-full h-96"
      src="https://picsum.photos/id/24/1200/700"
      height="400"
    />
  </l-carousel-item>
  <l-carousel-item>
    <img
      class="object-cover w-full h-96"
      src="https://picsum.photos/id/25/1200/700"
      height="400"
    />
  </l-carousel-item>
  <l-carousel-item>
    <img
      class="object-cover w-full h-96"
      src="https://picsum.photos/id/26/1200/700"
      height="400"
    />
  </l-carousel-item>
  <l-carousel-item>
    <img
      class="object-cover w-full h-96"
      src="https://picsum.photos/id/27/1200/700"
      height="400"
    />
  </l-carousel-item>
  <l-carousel-item>
    <img
      class="object-cover w-full h-96"
      src="https://picsum.photos/id/28/1200/700"
      height="400"
    />
  </l-carousel-item>
</l-carousel>
```

### Breakpoints

Use the `breakpoints` attribute (JSON) to override options at specific breakpoints. The carousel can deactivate itself at wider viewports.

```html
<style>
  .carousel-breakpoints {
    --slide-size: 80%;
    --slide-gap: 1rem;
    --button-border-color: #d3c9c9;
    height: 400px;
  }
  @media (min-width: 768px) {
    .carousel-breakpoints {
      --slide-size: 33%;
      --slide-gap: 1rem;
    }
  }
</style>
<l-carousel
  class="carousel-breakpoints"
  breakpoints='{"(min-width: 768px)": { "active": false }}'
>
  <l-carousel-item>
    <img
      class="object-cover"
      src="https://picsum.photos/id/17/1200/700"
      width="400"
      height="400"
      style="height: 400px"
    />
  </l-carousel-item>
  <l-carousel-item>
    <img
      class="object-cover"
      src="https://picsum.photos/id/18/1200/700"
      width="400"
      height="400"
      style="height: 400px"
    />
  </l-carousel-item>
  <l-carousel-item>
    <img
      class="object-cover"
      src="https://picsum.photos/id/19/1200/700"
      width="400"
      height="400"
      style="height: 400px"
    />
  </l-carousel-item>
</l-carousel>
```

### Autoplay

Set `autoplay` to a delay in milliseconds. Combine with `axis="y"` for vertical rotation.

```html
<l-carousel
  axis="y"
  autoplay="10000"
  duration="5"
  style="
    --slide-height: 36px;
    --button-size: 24px;
    --button-bg: transparent;
    --button-border-color: transparent;
    --button-arrow-color: white;
  "
>
  <l-carousel-item>
    <div
      class="py-2 px-4 lg:px-8 bg-gradient-to-r from-red-600 to-red-500 text-white font-bold text-center text-sm w-full whitespace-nowrap overflow-x-auto"
    >
      Free shipping on orders over $80
    </div>
  </l-carousel-item>
  <l-carousel-item>
    <div
      class="py-2 px-4 lg:px-8 bg-gradient-to-r from-red-600 to-red-500 text-white font-bold text-center text-sm w-full whitespace-nowrap overflow-x-auto"
    >
      4.9/5 (47 reviews) — Read reviews
    </div>
  </l-carousel-item>
</l-carousel>
```

## Examples

### Product gallery

Single slide with dots and fullscreen button.

```html
<l-carousel
  single
  with-dots
  with-fullscreen
>
  <l-carousel-item>
    <img
      class="object-cover w-full h-96"
      src="https://picsum.photos/id/20/1200/700"
      height="400"
    />
  </l-carousel-item>
  <l-carousel-item>
    <img
      class="object-cover w-full h-96"
      src="https://picsum.photos/id/21/1200/700"
      height="400"
    />
  </l-carousel-item>
  <l-carousel-item>
    <img
      class="object-cover w-full h-96"
      src="https://picsum.photos/id/22/1200/700"
      height="400"
    />
  </l-carousel-item>
</l-carousel>
```

### Product grid with scrollbar

Drag-free with scrollbar and outside navigation buttons.

```html
<l-carousel
  drag-free
  with-scrollbar
  scroll-buttons-position="outside"
  style="--slide-size: calc(100% / 3); --slide-gap: 1rem"
>
  <l-carousel-item>
    <img
      class="object-cover w-full h-96"
      src="https://picsum.photos/id/30/1200/700"
      height="400"
    />
  </l-carousel-item>
  <l-carousel-item>
    <img
      class="object-cover w-full h-96"
      src="https://picsum.photos/id/31/1200/700"
      height="400"
    />
  </l-carousel-item>
  <l-carousel-item>
    <img
      class="object-cover w-full h-96"
      src="https://picsum.photos/id/32/1200/700"
      height="400"
    />
  </l-carousel-item>
  <l-carousel-item>
    <img
      class="object-cover w-full h-96"
      src="https://picsum.photos/id/33/1200/700"
      height="400"
    />
  </l-carousel-item>
  <l-carousel-item>
    <img
      class="object-cover w-full h-96"
      src="https://picsum.photos/id/34/1200/700"
      height="400"
    />
  </l-carousel-item>
  <l-carousel-item>
    <img
      class="object-cover w-full h-96"
      src="https://picsum.photos/id/35/1200/700"
      height="400"
    />
  </l-carousel-item>
  <l-carousel-item>
    <img
      class="object-cover w-full h-96"
      src="https://picsum.photos/id/36/1200/700"
      height="400"
    />
  </l-carousel-item>
  <l-carousel-item>
    <img
      class="object-cover w-full h-96"
      src="https://picsum.photos/id/37/1200/700"
      height="400"
    />
  </l-carousel-item>
  <l-carousel-item>
    <img
      class="object-cover w-full h-96"
      src="https://picsum.photos/id/38/1200/700"
      height="400"
    />
  </l-carousel-item>
  <l-carousel-item>
    <img
      class="object-cover w-full h-96"
      src="https://picsum.photos/id/39/1200/700"
      height="400"
    />
  </l-carousel-item>
</l-carousel>
```

## Accessibility

### Criteria

- **Role** — Each `<l-carousel-item>` has `role="group"`
- **Dot navigation** — Dots use `role="tab"` with `aria-label` and `aria-selected`
- **Disabled buttons** — Previous/next buttons are `disabled` when at scroll boundaries

### Rules

- Add descriptive `aria-label` to the carousel element when context is needed
- Provide meaningful alt text on images inside carousel items

### Keyboard interactions

- `Tab` — Moves focus between navigation buttons
- `Enter` — Activates the focused button (next, previous, or dot)
- `Space` — Activates the focused button

## API reference

### Importing

```js
import 'luxen-ui/carousel';
import 'luxen-ui/carousel-item';
```

### Attributes & Properties

- **embla**: `EmblaCarouselType`
- **autoplay**: `number` (default: `0`) — Choose a delay between transitions in milliseconds (default: 4000).
- **autoplay-options**: `any` — Configure autoplay options.
- **axis**: `AxisOptionType` (default: `'x'`) — Choose scroll axis between x and y.
- **align**: `AlignmentOptionType` (default: `'start'`) — Align the slides relative to the carousel viewport.
- **breakpoints**: `any` (default: `{}`) — Breakpoint overrides for options.
- **loop**: `boolean` (default: `false`) — Enables infinite looping.
- **drag-free**: `boolean` (default: `false`) — Enables momentum scrolling (drag free).
- **duration**: `number` (default: `20`) — Set scroll duration when triggered by API methods.
- **skip-snaps**: `boolean` (default: `false`) — Allow skipping scroll snaps on vigorous drag.
- **slides-to-scroll**: `SlidesToScrollOptionType` (default: `1`) — Group slides together for navigation.
- **start-index**: `number` (default: `0`) — Set the initial scroll snap index.
- **contain-scroll**: `ScrollContainOptionType` (default: `'trimSnaps'`) — Clear leading and trailing empty space.
- **single**: `boolean` (default: `false`)
- **with-dots**: `boolean` (default: `false`)
- **with-scrollbar**: `boolean` (default: `false`)
- **with-fullscreen**: `boolean` (default: `false`)
- **dot-appearance**: `'circle' | 'bar'` (default: `'bar'`)
- **max-visible-dots**: `number` (default: `0`) — Maximum number of dots rendered at once. When the snap count exceeds this,
a sliding window keeps the active dot in view and shrinks the edge dot(s)
on the side where dots are hidden. `0` (default) renders all dots.
- **scroll-buttons-position**: `'inside' | 'outside'` (default: `'inside'`)
- **next**
- **previous**

### Methods

- **options()** → `EmblaOptionsType`
- **goToSlide(index: number, jump: boolean)**
- **slideNodes()**
- **slidesInView()**
- **isActive()**
- **renderFullscreenButton()**
- **renderNextPreviousButtons()**

### Events

- **select** — Fired when the active slide changes. Bubbles. Properties: `index: number`.
- **slides-in-view** — Fired when the set of slides in view changes. Properties: `indexes: number[]`.
- **fullscreen** — Fired when the fullscreen button is activated.

### CSS Parts

- `viewport` — The carousel viewport container.
- `container` — The slides container slot.
- `scroll-buttons` — The scroll buttons wrapper.
- `button` — Any navigation button.
- `button-previous` — The previous slide navigation button.
- `button-next` — The next slide navigation button.
- `button-dot` — Any dot navigation button.
- `dots` — The dots navigation wrapper.
- `button-fullscreen` — The fullscreen button.
- `button-icon` — Any button icon SVG.

### CSS custom properties

- `--slide-height` — Height of slides in vertical axis mode.
- `--slide-size` — Width of each slide (e.g. `100%`, `calc(100% / 3)`).
- `--slide-gap` — Gap between slides.
- `--button-size` — Size of navigation buttons.
- `--button-arrow-size` — Size of arrow icons inside buttons.
- `--button-arrow-color` — Color of arrow icons.
- `--button-offset` — Offset of inside-positioned buttons from edges.
- `--button-border-color` — Border color of buttons.
- `--button-border-radius` — Border radius of buttons.
- `--button-bg` — Background color of buttons.
- `--button-color` — Text/icon color of buttons.
- `--dot-color` — Color of inactive dots.
- `--dot-color-active` — Color of active dot.
- `--dot-margin` — Margin around dots container.
- `--dot-edge-scale` (default: `0.5`) — Scale factor applied to edge dots that signal more dots exist beyond the visible window ().

### `carousel-item` CSS custom properties

- `--aspect-ratio` — Aspect ratio of the slide.
