# ProductCarousel

> Horizontal product-card rail with unified multi-image and adaptive-video media.

Canonical URL: https://fa7e86e3d553:3005/islands/commerce/product-carousel

> Use for related products, new arrivals, cross-sells, and collection
> highlights. Each product card consumes the shared `media` array contract.

## Preview

> [Open the media-carousel interactive preview](https://storefront.trylexsis.com/v/island-preview-media-carousel-variations)

**Category**: Commerce

## Props

| Prop | Type | Default | Description |
|---|---|---|---|
| `products` | array | Required | Authored product objects |
| `title` | string | - | Section heading |
| `showQuickAdd` | boolean | `true` | Shows card Quick Add |
| `showWishlist` | boolean | `false` | Shows wishlist controls |
| `showLearnMore` | boolean | `true` | Shows product-page links |
| `showQuickView` | boolean | `false` | Shows quick-view triggers |
| `mediaTransition` | `"none" \| "fade" \| "slide" \| "zoom" \| "kenBurns"` | `"fade"` | Card-media transition |
| `hoverAdvance` | boolean | `true` | Enables hover previews for multi-media cards |
| `hoverAdvanceMode` | `"next" \| "cycle"` | `"next"` | Holds the next item or continuously cycles |
| `hoverInterval` | number | `1200` | Cycle interval in milliseconds |
| `cardVariant` | `"default" \| "compact" \| "compactRows"` | `"default"` | Card presentation |
| `animate` | boolean | `true` | Enables entrance and interaction motion |

## Product Media

Use `media` for all new product data. It is always an array.

```json
{
  "id": "product-1",
  "handle": "spoon-mug",
  "title": "Spoon Mug",
  "price": "$32.00",
  "media": [
    {
      "type": "image",
      "src": "https://cdn.example.com/mug-front.jpg",
      "alt": "Spoon mug front"
    },
    {
      "type": "image",
      "src": "https://cdn.example.com/mug-side.jpg",
      "alt": "Spoon mug side"
    },
    {
      "type": "video",
      "poster": "https://cdn.example.com/mug-poster.jpg",
      "sources": [
        { "url": "https://cdn.example.com/mug-demo.m3u8" },
        { "url": "https://cdn.example.com/mug-demo.mp4" }
      ]
    }
  ]
}
```

The legacy `image` field remains a boundary fallback. It is normalized to a
one-item image array before rendering. Do not introduce new singleton media
fields.

## Shopify Resolution

Use Shopify Product GIDs when live catalog data should be resolved by the
renderer:

```html
<lx-island name="ProductCarousel">
  <script type="application/json">
    {
      "productIds": [
        "gid://shopify/Product/1",
        "gid://shopify/Product/2",
        "gid://shopify/Product/3",
        "gid://shopify/Product/4"
      ],
      "showQuickAdd": true
    }
  </script>
</lx-island>
```

Use authored `products` for custom media, badges, subtitles, or controlled
preview data.

## Hover Preview Variations

### Swap To The Next Image

This is the standard ecommerce-card behavior. It advances immediately and
returns to the first item when the pointer leaves.

```html
<lx-island name="ProductCarousel">
  <script type="application/json">
    {
      "products": [],
      "hoverAdvance": true,
      "hoverAdvanceMode": "next",
      "showLearnMore": false
    }
  </script>
</lx-island>
```

### Cycle Through All Media

```html
<lx-island name="ProductCarousel">
  <script type="application/json">
    {
      "products": [],
      "hoverAdvance": true,
      "hoverAdvanceMode": "cycle",
      "hoverInterval": 900
    }
  </script>
</lx-island>
```

Hover behavior activates only when a product has more than one media item.
Touch users continue to use the card's internal swipe and media controls.

## Compact Rows

`cardVariant:"compactRows"` uses the first normalized media item as the row
thumbnail. Video items render their poster rather than autoplaying in the row.

## CSS Customization

Product cards expose the nested
[MediaCarousel](/islands/content/media-carousel) parts and variables. Common
hooks include:

| Part | Description |
|---|---|
| `root` | ProductCarousel root |
| `heading` | Section heading |
| `scroll-container` | Outer horizontal rail |
| `card-wrapper` | Individual product-card slot |
| `image` | Product media region |
| `slide` | Nested media slide |
| `previous`, `next` | Product-level media controls |
| `dots`, `dot` | Product-level media indicators |
| `nav-prev`, `nav-next` | Outer product rail controls |

```css
[data-section-id="related-products"] [data-part="card-wrapper"] {
  --lx-media-carousel-arrow-size: 2rem;
  --lx-media-carousel-arrow-bg: #fff;
  --lx-media-carousel-dot-active-color: #ed7f2d;
}
```

## Related Islands

- [MediaCarousel](/islands/content/media-carousel) - Canonical media contract and controls
- [FeaturedCollectionStage](/islands/commerce/featured-collection-stage) - Editorial shared-stage alternative
- [QuickAdd](/islands/commerce/quick-add) - Embedded card purchase action
- [ProductGallery](/islands/commerce/product-gallery) - PDP media gallery
