# Product gallery and media

> The product's images, videos and 3D models in depth. Covers how the gallery parts work together, galleries that follow the variant, videos outside the gallery, single images by position and image sizes.

Status: Ready (Smootify 2.0)  
URL: https://www.smootify.io/docs/astro/build/product-gallery  
Updated: 2026-10-21

The gallery shows the media of the Shopify product: its images, and if you want, its videos and 3D models. [Build the product page](https://www.smootify.io/docs/astro/build/product-page) introduces its four parts. This page goes further: how the parts work together, galleries that follow the chosen variant, videos and 3D models outside the gallery, single images by position, and image sizes.

> [!NOTE]
> Everything on this page goes inside `smootify-product`, set up as in [Build the product page](https://www.smootify.io/docs/astro/build/product-page). The images, videos and 3D models come from the product's media in Shopify, so upload them there. The entry's `images` and `media` fields hold them for the server render.

## How the parts work together

Put an element with `product="gallery"` inside `smootify-product`, and the parts you need inside it.

What Smootify needs:

- the `product="gallery"` element inside `smootify-product`;
- the parts inside that element: `gallery="slider"` on an element that holds a `[slider-track]`, `gallery="lightbox"` and `gallery="lightboxes"` on `a[lightbox-item]` links.

What is up to you:

- which parts you use, and where they sit: thumbnails under the slider or beside it, or no slider at all;
- the layout, the wrappers between the gallery element and its parts, the classes and the styles.

Four common ways to combine the parts:

| Layout | Parts inside `product="gallery"` | A click |
|---|---|---|
| Slider and thumbnails | `gallery="slider"`, `gallery="thumbnails"` | on a thumbnail, moves the slider |
| Slides that open full screen | `gallery="slider"`, with a Lightbox link in its first slide | on a slide, opens its picture full screen |
| A slider with a zoom link | `gallery="slider"`, `gallery="lightbox"` | on the zoom link, opens every picture full screen |
| A grid of pictures, no slider | `gallery="lightboxes"` | on a picture, opens it full screen, then the others |

The parts follow each other: when the visitor moves the slider with its arrows, its dots or a swipe, the matching thumbnail becomes the current one. When the product has nothing to show, the gallery element is hidden.

An element inside the slider belongs to the slides, not to the gallery. Keep thumbnails and lightbox links outside the slider. The one exception is an `a[lightbox-item]` link inside the first slide, as here:

```astro
---
const first = p.images[0];
---
<div product="gallery">
  <div gallery="slider">
    <div slider-track>
      <div><a href={first.url} lightbox-item><img src={first.url} alt={first.altText || p.name} /></a></div>
    </div>
  </div>
  <img gallery="thumbnails" src={first.url} alt={first.altText || p.name} />
</div>
```

Render the first picture of the entry in the first slide and in the thumbnail, so the page shows the featured image before Smootify loads.

With the link in the first slide, every slide opens full screen, and the viewer moves through all the slides.

### The slider

`gallery="slider"` goes on an element that holds a `[slider-track]`, whose children are the slides. Write one slide: Smootify copies the first slide once per picture and removes the other slides. Smootify moves between the slides by scrolling the track, so the site’s CSS gives the track `overflow-x: auto` and `scroll-snap-type`. The optional `[slider-prev]` and `[slider-next]` buttons and `[slider-dots]` element go inside the slider element: see [Write components](https://www.smootify.io/docs/astro/build/components). The arrows are disabled on the first and last slide, and the current dot gets `aria-current="true"`.

- **An image** goes on the Image inside the slide. A slide without an Image gets the picture as its background.
- **A video** uploaded to Shopify replaces what is inside the slide with a video player. It plays muted, on a loop, by itself. Add `data-controls` to the slide to give videos the player’s controls instead.
- **A YouTube or Vimeo video** replaces what is inside the slide with its player.
- **A 3D model** shows its preview image until its slide is shown. Only then does the 3D viewer load, so a visitor who never reaches that slide does not download it.

Videos and 3D models are in the slider only with `include-media` on the gallery element (see Videos and 3D models, below).

### Thumbnails

`gallery="thumbnails"` goes on the element that repeats once per picture: an `<img>`, or an `<a>` or `<div>` with an `<img>` inside. Write one, and Smootify repeats it in place.

- The thumbnail shows the picture on its Image, or as its background when it has no Image.
- For a video or a 3D model, the thumbnail shows the preview image.
- The current thumbnail gets the class `is-active` and `aria-current`. Style it in the component’s CSS.

Every slide, thumbnail and repeated lightbox also gets `data-media-type`, set to `image`, `video`, `external-video` or `model`. Custom CSS can use it, for example to put a play icon on the thumbnails of videos: see [CSS](https://www.smootify.io/docs/astro/developers/css).

### Lightboxes

- **`gallery="lightbox"`** on an `a[lightbox-item]` link opens every picture: the link takes the first media, and Smootify adds a hidden `a[lightbox-item]` after it for each other media, all in one group. The link keeps what you wrote in it, such as a zoom icon.
- **`gallery="lightboxes"`** on an `a[lightbox-item]` link repeats the link once per picture, each with its image. They form one group.
- Smootify writes the `href` of the full-size media on each link, with `data-media-type` and `data-lightbox-group`. For a video, an external video or a 3D model, the `href` is its preview image. Smootify does not draw the viewer: the site’s own, a library or a `<dialog>`, reads the links of a group and reads them again on `smootify:render`. See [Write components](https://www.smootify.io/docs/astro/build/components).

All the parts and what Smootify writes on them: [gallery parts](https://www.smootify.io/docs/astro/reference/attributes/gallery).

## Galleries that follow the variant

Without any option, the gallery shows every image of the product. When the visitor picks a variant that has an image, the slider moves to that image. Clicking a picture does not change the variant.

To show only the images of the chosen variant, add `variant-images` to the gallery element, with no value. In Shopify, you link an image to a variant in the variant’s settings. Smootify then groups the images in one of two ways, by position or by alt text.

The options are set per gallery. One gallery on a page can follow the variant while another one shows every picture.

Pick a colour and switch between the two ways to see which images the gallery shows:

Example: a t-shirt in Red, Blue and Green with eight images in this order: 1 a photo of the model (no color), 2-4 Red (2 is the image of the Red variant), 5-6 Blue (5 is the image of Blue), 7-8 Green (7 is the image of Green). By position, Red shows 2, 3, 4; Blue 5, 6; Green 7, 8; image 1 is never shown. By alt text (2-8 end with "# Red", "# Blue", "# Green", 1 has no tag), Red shows 1, 2, 3, 4.

### By position

This is how `variant-images` groups the images when it has no value. Each image linked to a variant starts a group, and the group runs until the next linked image.

Take a chair sold in Oak and Walnut, with five images in this order in Shopify:

| Image in Shopify | Linked to | Shown when the visitor picks |
|---|---|---|
| 1. The chair in a room | no variant | only a variant without an image |
| 2. Oak, front | Oak | Oak |
| 3. Oak, detail | no variant | Oak |
| 4. Walnut, front | Walnut | Walnut |
| 5. Walnut, detail | no variant | Walnut |

A variant without an image of its own shows every image. The images before the first linked one belong to no group: once the visitor picks Oak or Walnut, the room picture is gone. For pictures that belong to every variant, group the images by alt text.

### By alt text

Give the attribute the value `alt`: `variant-images="alt"`. Each image then goes with the variants that its alt text names after the last `#`. An image without a tag shows for every variant. With `include-media`, videos, YouTube and Vimeo videos and 3D models are grouped the same way, by their own alt text.

- `Oak chair, front # Oak` shows for every Oak variant.
- `Oak chair # Oak / Steel` shows only for the variant with both values. Put a slash with a space on each side between the values, so a value such as `Black/White` stays one value.
- `#Wood_Oak` (the option name, an underscore, the value) also works.

Capital letters and the spaces around the values do not matter, but each value must be one of the variant’s values. You write the alt text in Shopify, on each image and video.

The alt text is public, tag included: screen readers and search engines read it. Write it so that it makes sense read aloud.

```astro
---
const first = p.images[0];
---
<div product="gallery" include-media variant-images="alt">
  <div gallery="slider">
    <div slider-track>
      <div data-controls><img src={first.url} alt={first.altText || p.name} /></div>
    </div>
  </div>
</div>
```

## Videos and 3D models

### In the gallery

Add `include-media` to the gallery element. The gallery then shows, in the order of the product’s media in Shopify, the images, the videos uploaded to the product, YouTube and Vimeo videos, and 3D models. Without it, the gallery shows images only.

A 3D model becomes a 3D viewer in the slider only if its file in Shopify is a GLB or glTF file. Without one, its preview image stays in its place.

### Outside the gallery

To show videos in a section of their own, use these attributes on elements inside `smootify-product`:

| Attribute | Put it on | What it shows |
|---|---|---|
| `product="video"` | an element with a `<video>` inside, or an `a[lightbox-item]` link | the first video uploaded to the product |
| `product="videos"` | the same | every video, one copy of the element each |
| `product="external-video"` | an element, or an `a[lightbox-item]` link | the first YouTube or Vimeo video |
| `product="external-videos"` | the same | every YouTube or Vimeo video, one copy each |
| `product="model"` | an element | a 3D viewer for each model |

- **On an `a[lightbox-item]` link**, the `<img>` inside shows the video’s preview, and the link gets `data-media-type`. The site’s viewer decides how to play it.
- **On an element with a `<video>` inside**, Smootify adds the product’s video sources to that `<video>`.
- **On an element** for a YouTube or Vimeo video, the player fills the element. Give the element a size in your design.
- **In a slider**, `product="videos"` and `product="external-videos"` become a slider when they contain a `[slider-track]`: one slide per video, each a copy of the first slide whose content is replaced by the video, so anything you design inside the slide is not kept. Smootify runs the `[slider-prev]`, `[slider-next]` and `[slider-dots]` inside the element. On a product without videos of that kind, the first slide stays as you wrote it.
- **A product without videos** of that kind loses the element.

`product="model"` loads the 3D viewer only on a product that has a model. On a product without one, the element stays as you wrote it. Its attributes that start with `data-` go to the viewer under the name after `data-`: `data-auto-rotate` makes the model turn by itself.

```html
<div>
  <a href="#" lightbox-item product="videos"><img alt=""></a>
  <div product="external-videos"></div>
</div>
```

## One image by position

`product="specific-image"` shows one image of the product, chosen by its position among the images. Videos and 3D models do not count.

- `index="0"` is the first image, `index="1"` the second, and so on.
- Without `index`, it shows the second image, for example for a card that shows another picture on hover.
- When the product has no image at that position, the element is removed.

Put it on an `<img>`, or on another element to use the picture as its background. It works in [product cards](https://www.smootify.io/docs/astro/build/product-cards) and [variant cards](https://www.smootify.io/docs/astro/build/variants-list) too. For the image of the chosen variant, which changes with the variant, use `variant="image"`.

## Image sizes

Without size attributes, the page downloads each Shopify image at its full size. These attributes ask the Shopify CDN for a smaller file. Here on an image of 2000 × 1500 pixels:

Example: a Shopify image of 2000 × 1500 pixels.

| Attribute | What the page downloads | Needs |
|---|---|---|
| `max-width="800"` | the image at most 800 pixels wide: 800 × 600 | nothing else |
| `max-height="800"` | the image at most 800 pixels high: 1067 × 800 | nothing else |
| `crop="center"` | a larger image cropped to both sizes, starting from that point: 800 × 800, cut from the center | `max-width` and `max-height` |
| `pad-color="ffffff"` | a smaller image with the space around it filled with that color: 800 × 600 inside 800 × 800 of white | `max-width` and `max-height` |

Where they go:

- for the slides, on the `gallery="slider"` element (not on a slide);
- for thumbnails and repeated lightboxes, on the element with the `gallery` attribute;
- for single images, on the element with `product="specific-image"` or `variant="image"`.

They work only on images that Smootify fills from Shopify, not on an `<img>` that Smootify does not fill. Every image they work on: [image size](https://www.smootify.io/docs/astro/reference/attributes/image-size).

## Before you publish

> [!STUCK]
> - **Videos or 3D models are missing.** Add `include-media` to the `product="gallery"` element.
> - **The first picture disappears when a variant is picked.** With `variant-images` and no value, the images before the first linked image belong to no variant. Group the images by alt text instead.
> - **The slides you designed are gone.** Only the first slide is the template: Smootify removes the others.
> - **Image sizes do nothing on the slides.** Put `max-width` and the other size attributes on the `gallery="slider"` element, not on a slide.
> - **A 3D model shows only a picture.** In thumbnails and lightboxes a model is always its preview image. In the slider, the model needs a GLB or glTF file in Shopify.
> - **Screen readers read "# Oak" aloud.** The tag is part of the public alt text. Write the alt text as a phrase that ends with the tag.
> - **The gallery does not move.** The slider element has no `[slider-track]`, or the site's CSS does not make the track scroll: it needs `overflow-x: auto` and `scroll-snap-type`.
> - **A zoom link does nothing.** Smootify only writes the links. The site must bring a viewer that reads `a[lightbox-item]`.
