---
name: carousel
category: disclosure
summary: "Content slider with dots, autoplay, loop and drag (Embla engine)"
subpath: "@42/core/carousel"
---

Content slider with prev/next, dot indicators, autoplay, loop and pointer drag.
The scroll/snap engine (drag physics, momentum, snapping, loop, resize, axis) is
powered by [Embla Carousel](https://www.embla-carousel.com/); the controller
adds the headless layer (ARIA, dots, keyboard, autoplay, typed events).

```html
<div data-c42-carousel>
  <div data-c42-carousel-viewport>
    <div data-c42-carousel-track>
      <div data-c42-carousel-slide>One</div>
      <div data-c42-carousel-slide>Two</div>
      <div data-c42-carousel-slide>Three</div>
    </div>
  </div>
  <button data-c42-carousel-prev aria-label="Previous slide">‹</button>
  <button data-c42-carousel-next aria-label="Next slide">›</button>
  <div data-c42-carousel-dots></div>
</div>
```

```ts
import { Carousel } from '@42/core/carousel';
const carousel = new Carousel(root, { loop: true, autoplay: false, swipe: true });
carousel.next();
carousel.on('carousel:change', (e) => console.log(e.detail.index));
```

The active index is reflected as `data-active="true"` on the current slide/dot
and as `data-active-index` on the root. Embla applies the transform to the
`[data-c42-carousel-track]` element, so wrap the track in
`[data-c42-carousel-viewport]` (the clipping/overflow element). Dots are
auto-generated into `[data-c42-carousel-dots]` (one `[data-c42-carousel-dot]`
per slide) unless you provide your own. Slide width/per-view is controlled in
CSS via the slide's `flex-basis` (default `0 0 100%` = one slide per view).

Keyboard (root focused): Left/Right move, Home/End jump to first/last.
Pointer: drag/swipe is handled by Embla (disable with `swipe: false`).
Options: `defaultIndex` (0), `loop` (false), `axis` ('x'), `align` ('center'), `slidesToScroll` (1), `dragFree` (false), `swipe` (true), `autoplay` (false), `autoplayInterval` (4000), `pauseOnHover` (true)
Methods: `next()`, `prev()`, `goTo(i)`, `play()`, `pause()`, `index`, `length`
Events: `carousel:change` → `{ index, previousIndex }`
