---
title: Lightbox Carousel
description: "Astro image carousels that open the chosen slide in a larger view."
seo:
    title: "Lightbox Carousel for Astro — examples and usage"
---

```astro
---
import { Image } from "astro:assets"
import {
  LightboxCarousel,
  LightboxCarouselContent,
  LightboxCarouselItem,
  LightboxCarouselNext,
  LightboxCarouselPrevious,
} from "@/components/ui/lightbox-carousel"

const images = [
  {
    src: "https://images.unsplash.com/photo-1470770841072-f978cf4d019e?w=1200&h=800&auto=format&fit=crop",
    width: 1200,
    height: 800,
    alt: "Mountains reflected in a lake",
  },
  {
    src: "https://images.unsplash.com/photo-1441974231531-c6227db76b6e?w=1200&h=800&auto=format&fit=crop",
    width: 1200,
    height: 800,
    alt: "Sunlight through forest trees",
  },
  {
    src: "https://images.unsplash.com/photo-1500530855697-b586d89ba3ee?w=1200&h=800&auto=format&fit=crop",
    width: 1200,
    height: 800,
    alt: "Open landscape in evening light",
  },
  {
    src: "https://images.unsplash.com/photo-1464822759023-fed622ff2c3b?w=1200&h=800&auto=format&fit=crop",
    width: 1200,
    height: 800,
    alt: "A mountain peak above the clouds",
  },
  {
    src: "https://images.unsplash.com/photo-1472396961693-142e6e269027?w=1200&h=800&auto=format&fit=crop",
    width: 1200,
    height: 800,
    alt: "Deer in a green forest",
  },
  {
    src: "https://images.unsplash.com/photo-1447752875215-b2761acb3c5d?w=1200&h=800&auto=format&fit=crop",
    width: 1200,
    height: 800,
    alt: "A path through tall trees",
  },
]
---

<div class="mx-auto w-full max-w-3xl px-14 py-4">
  <LightboxCarousel>
    <LightboxCarouselContent>
      {images.map((image) => (
        <LightboxCarouselItem alt={image.alt}>
          <Image
            slot="preview"
            {...image}
            alt=""
            class="aspect-3/2 w-full object-cover"
            loading="lazy"
          />
          <Image slot="content" {...image} loading="lazy" />
        </LightboxCarouselItem>
      ))}
    </LightboxCarouselContent>
    <LightboxCarouselPrevious />
    <LightboxCarouselNext />
  </LightboxCarousel>
</div>
```

## Installation

```bash
bunx --bun shadcn@latest add @gnosticai/lightbox-carousel
```

The command also installs [Lightbox](/components/lightbox) and
[Carousel](/components/carousel).

## Usage

Compose the page carousel from the same parts as `Carousel`. Each item needs a
`preview` slot and a `content` slot. `preview` is the slide on the page.
`content` is the slide in the enlarged dialog. Click a slide to open that
image. Previous and Next in the dialog continue through the same list. Close
the dialog and the page carousel shows the slide you were viewing.

```astro
---
import { Image } from "astro:assets"
import {
  LightboxCarousel,
  LightboxCarouselContent,
  LightboxCarouselItem,
  LightboxCarouselNext,
  LightboxCarouselPrevious,
} from "@/components/ui/lightbox-carousel"
import lake from "../assets/lake.jpg"
---

<LightboxCarousel>
  <LightboxCarouselContent>
    <LightboxCarouselItem alt="Mountains reflected in a lake">
      <Image slot="preview" src={lake} alt="" class="aspect-3/2 w-full object-cover" />
      <Image slot="content" src={lake} alt="Mountains reflected in a lake" />
    </LightboxCarouselItem>
  </LightboxCarouselContent>
  <LightboxCarouselPrevious />
  <LightboxCarouselNext />
</LightboxCarousel>
```

Arrow keys move the open carousel. Escape, the close button, and an overlay
click close the dialog. The carousel loops.

Keep links and buttons out of `preview`. That slot is already inside a button.

## Several slides

Set the item basis to show more than one slide. `caption` appears under the
enlarged image.

```astro
---
import { Image } from "astro:assets"
import {
  LightboxCarousel,
  LightboxCarouselContent,
  LightboxCarouselItem,
  LightboxCarouselNext,
  LightboxCarouselPrevious,
} from "@/components/ui/lightbox-carousel"

const images = [
  {
    src: "https://images.unsplash.com/photo-1470770841072-f978cf4d019e?w=1200&h=800&auto=format&fit=crop",
    width: 1200,
    height: 800,
    alt: "Mountains reflected in a lake",
    caption: "A quiet mountain lake.",
  },
  {
    src: "https://images.unsplash.com/photo-1441974231531-c6227db76b6e?w=1200&h=800&auto=format&fit=crop",
    width: 1200,
    height: 800,
    alt: "Sunlight through forest trees",
    caption: "Morning light between the trees.",
  },
  {
    src: "https://images.unsplash.com/photo-1464822759023-fed622ff2c3b?w=1200&h=800&auto=format&fit=crop",
    width: 1200,
    height: 800,
    alt: "A mountain peak above the clouds",
    caption: "The ridge stays above the cloud line.",
  },
  {
    src: "https://images.unsplash.com/photo-1500530855697-b586d89ba3ee?w=1200&h=800&auto=format&fit=crop",
    width: 1200,
    height: 800,
    alt: "Open landscape in evening light",
    caption: "The valley holds the last light.",
  },
]
---

<div class="mx-auto w-full max-w-3xl px-14 py-4">
  <LightboxCarousel label="Landscape gallery">
    <LightboxCarouselContent class="-ml-4">
      {images.map(({ caption, ...image }, i) => (
        <LightboxCarouselItem
          alt={image.alt}
          caption={caption}
          class="basis-1/2 pl-4 @min-xl/carousel:basis-1/3"
        >
          <Image
            slot="preview"
            {...image}
            alt={`Image ${i + 1}`}
            class="aspect-3/2 w-full object-cover"
            loading={i === 0 ? "eager" : "lazy"}
          />
          <Image slot="content" {...image} loading="lazy" />
        </LightboxCarouselItem>
      ))}
    </LightboxCarouselContent>
    <LightboxCarouselPrevious />
    <LightboxCarouselNext />
  </LightboxCarousel>
</div>
```

## API

`LightboxCarousel` accepts native div attributes and these options:

| Prop    | Type     | Default         | Purpose                                |
| ------- | -------- | --------------- | -------------------------------------- |
| `label` | `string` | `Image gallery` | Accessible name for the page carousel. |

`LightboxCarouselContent` accepts the same attributes as `CarouselContent`.
`LightboxCarouselPrevious` and `LightboxCarouselNext` accept the same
attributes as the carousel controls.

`LightboxCarouselItem` accepts native div attributes and these options:

| Prop        | Type      | Default  | Purpose                                                  |
| ----------- | --------- | -------- | -------------------------------------------------------- |
| `alt`       | `string`  | Required | Slide button name and dialog title.                      |
| `caption`   | `string`  | —        | Optional text under the enlarged image.                  |
| `hoverZoom` | `boolean` | `true`   | Scale the slide preview on hover with `hover:scale-105`. |

Both `preview` and `content` slots are required. The page carousel is one
slide wide unless you set `basis` on the item. Spacing follows `Carousel`:
pair a negative margin on `LightboxCarouselContent` with padding on each item.

## When to use Lightbox Carousel

Compose the thumbnail carousel and lightbox parts around the same ordered images. Use stable image order so the enlarged view matches the selected thumbnail. Pass carousel options through the existing props.

## Keyboard and behavior

Embla supplies slide movement and the dialog controller supplies modal focus. Keep labelled previous, next, and close controls. Check keyboard use in both the page carousel and the enlarged view.

## Theme and layout

Use small thumbnail sources and suitable full-size images to limit transfer size. Check aspect ratios and captions at narrow widths. The component does not generate image derivatives or load a media library for you.

## Related choices

Use [Carousel](/components/carousel) without a modal or [Lightbox Grid](/components/lightbox-grid) for a page of thumbnails.
