> For the complete documentation index, see [llms.txt](https://analog.groupthought.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://analog.groupthought.com/reference/alpine/slideshow.md).

# x-slideshow

Directives and magics for slideshows: slide registration, autoplay, and controls that stay in sync.

Directives and magics for slideshows: slide registration, autoplay, and controls that stay in sync.

| Directive / magic                                               | What it does                                                                                                                                                    |
| --------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `x-slideshow`                                                   | The root. Holds the play state and the current slide index                                                                                                      |
| `x-slideshow.autoplay`                                          | Starts the show playing on load                                                                                                                                 |
| `x-slideshow.duration.5000ms`                                   | Sets how long each slide shows (default 1000ms)                                                                                                                 |
| `x-slideshow="{ initialSlideIndex: 2 }"`                        | Options object. `state` and `currentSlideIndex` accept get/set pairs                                                                                            |
| `x-slideshow:viewport`                                          | Wraps the slides. Adds a carousel region, arrow-key navigation, and the `$id('slideshow')` id                                                                   |
| `x-slideshow:slide`                                             | Registers a slide (`role="group"`, `aria-roledescription="slide"`)                                                                                              |
| `x-slideshow:prev` / `x-slideshow:next`                         | Step buttons. Pause the show, then move                                                                                                                         |
| `x-slideshow:play` / `x-slideshow:pause` / `x-slideshow:toggle` | Play-state buttons                                                                                                                                              |
| `x-slideshow:control`                                           | Binds `aria-controls` to the viewport for a custom control                                                                                                      |
| `$slideshow`                                                    | The state, readable anywhere inside the root: `currentSlideIndex`, `totalSlides`, `next()`, `prev()`, `play()`, `pause()`, `toggle()`, `state`, `slideDuration` |
| `$slide`                                                        | Inside `x-slideshow:slide`: `slideIndex`, `isCurrentSlide`, `wasLastSlide`                                                                                      |

Left and right arrow keys change slides. Focus pauses autoplay. Slide changes are announced only while paused because `aria-live` changes to `"off"` during autoplay.

## Examples

### A basic slideshow

Use `x-slideshow:slide` with `$slide.isCurrentSlide` to show one slide at a time:

```html
<div x-slideshow>
  <div x-slideshow:viewport>
    <div x-slideshow:slide x-show="$slide.isCurrentSlide">First</div>
    <div x-slideshow:slide x-show="$slide.isCurrentSlide">Second</div>
  </div>
  <button x-slideshow:prev>Previous</button>
  <button x-slideshow:next>Next</button>
</div>
```

### Autoplay

Use the `autoplay` and `duration` modifiers to advance slides on a timer:

```html
<div x-slideshow.autoplay.duration.5000ms>
  …
  <button x-slideshow:toggle>Play / pause</button>
</div>
```

`x-slideshow:prev` and `x-slideshow:next` pause before changing slides. Add an `x-slideshow:toggle` or `x-slideshow:pause` button to an autoplaying slideshow. The viewport also pauses on focus.

### Transitions between slides

Use `x-transition` on the slides, with `$slide.wasLastSlide` to style the slide on its way out:

```html
<div
  x-slideshow:slide
  x-show="$slide.isCurrentSlide"
  x-transition:enter="duration-300"
  x-transition:enter-start="opacity-0"
  x-transition:leave="duration-300 !absolute top-0 left-0 w-full"
  x-transition:leave-end="opacity-0"
>
  …
</div>
```

`wasLastSlide` marks the slide that was current before the latest change. It is mid-exit while the new slide enters.

### A progress bar

Use a CSS animation with the `--slideshow-duration` and `--slideshow-play-state` properties set by the root. This keeps smooth progress out of Alpine's reactive loop:

```html
<ol class="flex gap-2">
  <template
    x-for="index in Array.from({ length: $slideshow.totalSlides }, (_, index) => index)"
    :key="index"
  >
    <li class="h-px grow overflow-hidden">
      <span
        class="slideshow-progress block size-full bg-content"
        :data-current="index === $slideshow.currentSlideIndex ? 'true' : 'false'"
      ></span>
    </li>
  </template>
</ol>

<style>
  @keyframes slideshow-progress {
    from {
      transform: scaleX(0);
    }

    to {
      transform: scaleX(1);
    }
  }

  .slideshow-progress {
    transform: scaleX(0);
    transform-origin: left;
  }

  .slideshow-progress[data-current="true"] {
    animation: slideshow-progress var(--slideshow-duration, 1s) linear both;
    animation-play-state: var(--slideshow-play-state, paused);
  }
</style>
```

The animation pauses and resumes with the slideshow. Moving to another slide removes the animation from the old segment and starts it on the new one.

### Opening on a specific slide

Use the `initialSlideIndex` option to pick the opening slide:

```html
<div x-slideshow="{ initialSlideIndex: 2 }">…</div>
```

The product gallery uses this to open on the featured media of the selected variant.

### Driving the slideshow from outside

Use get/set pairs in the options object to bind the slide index to your own state:

```html
<div
  x-data="{
    get currentSlideIndex() { return $slideshow.currentSlideIndex },
    set currentSlideIndex(value) { $slideshow.currentSlideIndex = value }
  }"
  x-slideshow
  :data-current-slide="currentSlideIndex"
>
  …
</div>
```

Anything inside the root can also set `$slideshow.currentSlideIndex` directly. The product gallery's thumbnail picker and variant-change handler both jump slides this way.

## Options

| Option              | What it does                                                          |
| ------------------- | --------------------------------------------------------------------- |
| `initialSlideIndex` | The slide index to open on (default `0`)                              |
| `state`             | `'playing'` or `'paused'`. Accepts a get/set pair for two-way binding |
| `currentSlideIndex` | The current slide. Accepts a get/set pair for two-way binding         |

`autoplay` and `slideDuration` are set through the modifiers, not the options object. To sync a slideshow with an accordion or tabs in a Pair section, see [Pair sections](/building-pages/pair.md).
