> 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/scroll-list.md).

# x-scroll-list

Directives and a magic for scroll-snap lists: item registration, visibility tracking, and buttons that page through the list.

Directives and a magic for scroll-snap lists: item registration, visibility tracking, and buttons that page through the list.

| Directive / magic                           | What it does                                                                                                                                            |
| ------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `x-scroll-list`                             | The root. Also acts as the viewport and scroller until descendants claim those roles                                                                    |
| `x-scroll-list.vertical`                    | Column list: scrolling, alignment, and centering run on the y axis                                                                                      |
| `x-scroll-list="{ initialItemIndex: 2 }"`   | Options object                                                                                                                                          |
| `x-scroll-list:viewport`                    | The element items are measured against. Uses the `$id('scrollList')` id                                                                                 |
| `x-scroll-list:scroller`                    | The scroll container that `scrollTo` moves                                                                                                              |
| `x-scroll-list:item`                        | Registers an item                                                                                                                                       |
| `x-scroll-list:prev` / `x-scroll-list:next` | Step buttons. Scroll the previous or next offscreen item into view                                                                                      |
| `$scrollList`                               | The state, readable anywhere inside the root: `isScrolling`, `items`, `visibleIndices`, `centeredIndex`, `scrollTo(index, options)`, `next()`, `prev()` |

An item counts as visible at 50% intersection with the viewport; `visibleIndices` lists those items and `centeredIndex` is the item crossing the viewport's center line. `next()` scrolls the first item after the visible ones to the start of the viewport, so the buttons page by whole viewports rather than one item at a time.

## Examples

### A basic scroll list

Use `x-scroll-list:scroller` on the overflow container and `x-scroll-list:item` on each child:

```html
<div x-scroll-list>
  <div x-scroll-list:scroller class="flex overflow-x-auto snap-x snap-mandatory">
    <div x-scroll-list:item class="snap-start">First</div>
    <div x-scroll-list:item class="snap-start">Second</div>
  </div>
  <button x-scroll-list:prev>Previous</button>
  <button x-scroll-list:next>Next</button>
</div>
```

Add the scroll-snap classes yourself. The plugin tracks and scrolls while CSS handles snapping. `product-media-mobile.liquid` uses this structure.

### Opening at an item

Use the `initialItemIndex` option to scroll an item into view on mount, without animation:

```html
<div x-scroll-list="{ initialItemIndex: 2 }">…</div>
```

The mobile product gallery opens on the featured media of the selected variant this way.

### A vertical list

Use the `vertical` modifier when the scroller is a column:

```html
<div x-scroll-list.vertical>
  <div x-scroll-list:scroller class="flex flex-col overflow-y-auto">…</div>
</div>
```

The desktop thumbnail picker (`product-media-thumbnail-picker.liquid`) uses this for its column of thumbnails.

### Tracking the centered item

Use `$scrollList.centeredIndex` to react to whichever item sits in the middle of the viewport:

```html
<div aria-live="polite">
  <span x-text="$scrollList.centeredIndex + 1">1</span> /
  <span x-text="$scrollList.items.length">1</span>
</div>
```

The gallery's position indicator reads it, and the video and 3D-model media items `$watch` it to pause themselves when they scroll out of the center.

### Jumping to an item

Use `$scrollList.scrollTo(index, options)` to scroll programmatically:

```html
<div @shopify:product:select.window="$scrollList.scrollTo(3, { behavior: 'auto' })">
  …
</div>
```

`options` takes `behavior` (`'smooth'` by default) and `align`: `'start'`, `'center'`, or `'end'` against the viewport. The gallery jumps to the variant's featured media this way. Assigning `$scrollList.centeredIndex = 3` also scrolls, which is what makes the get/set binding to a slideshow work.

## Options

| Option             | What it does                                                   |
| ------------------ | -------------------------------------------------------------- |
| `initialItemIndex` | The item to scroll into view on mount, instantly (default `0`) |

`x-carousel` builds on this plugin. Its root composes `x-scroll-list`, its track is the scroller, and its items are scroll-list items. Analog's card lists use `x-carousel`; the product gallery uses `x-scroll-list` directly and composes its own controls.
