"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>value.value.Navigation
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.
"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
ariaLabel, and the arrows with previousAriaLabel and nextAriaLabel.playLabel, pauseLabel, and renderStatusText in non-English apps; their defaults are English.