Skip to main content

Carousel Gallery

Carousel Gallery is a widget that shows media one item at a time, such as product photos or a slideshow.

Import

import { CarouselGallery } from '@vortexlabs/vortex';
import type { CarouselGalleryProps } from '@vortexlabs/vortex';

Allied components

Other links

"use client";

import { CarouselGallery, Placeholder, Stack } from "@vortexlabs/vortex";

const photos = ["1", "2", "3", "4", "5", "6"];

export const CarouselGalleryExample = () => {
  return (
    <Stack width="100%" maxWidth="480px">
      <CarouselGallery ariaLabel="Project photos" defaultValue="3">
        <CarouselGallery.Viewport>
          {photos.map((value) => (
            <CarouselGallery.Item key={value} value={value}>
              <Placeholder height="320px" minWidth={0}>
                Photo {value}
              </Placeholder>
            </CarouselGallery.Item>
          ))}
          <CarouselGallery.Controls
            previousAriaLabel="Previous photo"
            nextAriaLabel="Next photo"
            size="sm"
          />
          <CarouselGallery.Indicator />
        </CarouselGallery.Viewport>
      </CarouselGallery>
    </Stack>
  );
};

Features

  • Shows one item per view and moves one item per step.
  • Offers swipe navigation, overlay arrows, indicators, and thumbnails.
  • Supports controlled selection, autoplay, and lazy mounting.
  • Supports RTL layouts and reduced-motion preferences.

Anatomy

<CarouselGallery ariaLabel="Project photos">
<CarouselGallery.Viewport>
  <CarouselGallery.Item value="front">Front</CarouselGallery.Item>
  <CarouselGallery.Item value="side">Side</CarouselGallery.Item>
  <CarouselGallery.Controls previousAriaLabel="Previous photo" nextAriaLabel="Next photo" />
  <CarouselGallery.Indicator />
</CarouselGallery.Viewport>
<CarouselGallery.Thumbnails ariaLabel="Choose a photo">
  <CarouselGallery.Thumbnail value="front" ariaLabel="Show front">Front</CarouselGallery.Thumbnail>
  <CarouselGallery.Thumbnail value="side" ariaLabel="Show side">Side</CarouselGallery.Thumbnail>
</CarouselGallery.Thumbnails>
</CarouselGallery>
Component Part
Description
Holds the active item and names the gallery.
Slides between items, one at a time.
Shows one slide, identified by its value.
Moves to the previous or next item with arrows over the slides.
Shows the position of the active item.
Holds the thumbnail picker.
Selects the item with the same value.

Each item needs a unique value; defaultValue picks the first one shown. Control selection with value and onChange. Indicator dots only show position, and arrows="hover" shows the arrows on hover or focus.

Showing photo 1
"use client";

import { CarouselGallery, Placeholder, Stack, Text } from "@vortexlabs/vortex";
import { useState } from "react";

const photos = ["1", "2", "3", "4", "5", "6"];

export const CarouselGalleryNavigationExample = () => {
  const [value, setValue] = useState("1");

  return (
    <Stack width="100%" maxWidth="480px" gap={3}>
      <CarouselGallery
        ariaLabel="Navigation"
        value={value}
        onChange={({ value }) => setValue(value)}
      >
        <CarouselGallery.Viewport>
          {photos.map((value) => (
            <CarouselGallery.Item key={value} value={value}>
              <Placeholder height="320px" minWidth={0}>
                Photo {value}
              </Placeholder>
            </CarouselGallery.Item>
          ))}
          <CarouselGallery.Controls
            previousAriaLabel="Previous photo"
            nextAriaLabel="Next photo"
            arrows="hover"
          />
          <CarouselGallery.Indicator />
        </CarouselGallery.Viewport>
      </CarouselGallery>
      <Text>Showing photo {value}</Text>
    </Stack>
  );
};

Thumbnails

Each Thumbnail is a button matched to an item by value, so don't nest links or buttons. position puts them at the bottom (default) or start, and is responsive.

"use client";

import { CarouselGallery, Placeholder, Stack } from "@vortexlabs/vortex";

const photos = ["1", "2", "3", "4", "5", "6"];

export const CarouselGalleryThumbnailsExample = () => {
  return (
    <Stack width="100%" maxWidth="640px">
      <CarouselGallery ariaLabel="Thumbnail gallery">
        <CarouselGallery.Viewport>
          {photos.map((value) => (
            <CarouselGallery.Item key={value} value={value}>
              <Placeholder height="320px" minWidth={0}>
                Photo {value}
              </Placeholder>
            </CarouselGallery.Item>
          ))}
        </CarouselGallery.Viewport>
        <CarouselGallery.Thumbnails
          ariaLabel="Choose a photo"
          position={{ xs: "bottom", md: "start" }}
        >
          {photos.map((value) => (
            <CarouselGallery.Thumbnail
              key={value}
              value={value}
              ariaLabel={`Show photo ${value}`}
              width="64px"
            >
              <Placeholder height="48px" minWidth={0}>
                {value}
              </Placeholder>
            </CarouselGallery.Thumbnail>
          ))}
        </CarouselGallery.Thumbnails>
      </CarouselGallery>
    </Stack>
  );
};

Playback and Lazy Mounting

autoPlay adds a play/pause button and advances every autoPlayInterval milliseconds until the last item. It pauses on hover, offscreen, or in a hidden tab, and stops after user navigation. With reduced motion, it waits for play.

lazyMount mounts items as users reach them. Give placeholder the content's height to avoid layout shift.

"use client";

import { CarouselGallery, Placeholder, Stack } from "@vortexlabs/vortex";

const photos = ["1", "2", "3", "4", "5", "6"];

export const CarouselGalleryPlaybackExample = () => {
  return (
    <Stack width="100%" maxWidth="480px">
      <CarouselGallery
        ariaLabel="Autoplay"
        autoPlay
        autoPlayInterval={3000}
        playLabel="Play slides"
        pauseLabel="Pause slides"
        lazyMount
      >
        <CarouselGallery.Viewport>
          {photos.map((value) => (
            <CarouselGallery.Item
              key={value}
              value={value}
              placeholder={
                <Placeholder height="320px" minWidth={0}>
                  Loading photo
                </Placeholder>
              }
            >
              <Placeholder height="320px" minWidth={0}>
                Photo {value}
              </Placeholder>
            </CarouselGallery.Item>
          ))}
          <CarouselGallery.Indicator />
        </CarouselGallery.Viewport>
      </CarouselGallery>
    </Stack>
  );
};

Accessibility

Key
Description
TabShiftTab
Move forward or backward through focusable elements.
EnterSpace
Activate a focused arrow, thumbnail, or playback button.
Left arrowRight arrow
Move focus between thumbnails when three or more are available.
HomeEnd
Focus the first or last thumbnail when three or more are available.
Announces the visible position after each move, but not during autoplay.
Name the gallery and thumbnails with ariaLabel, and the arrows with previousAriaLabel and nextAriaLabel.
Set playLabel, pauseLabel, and renderStatusText in non-English apps; their defaults are English.