Image carousel

A swipeable gallery of images with arrows, dots, and thumbnails.

Modern layout
Classic layout
Bold layout
Editorial layout
1 / 4

Modern — bold type on an asymmetric grid

Installation
$Terminal
npx shadcn@latest add https://sdk-components.thesqd.com/r/image-carousel.json
Usage
Import the master file and pass an array of images. The frame reuses the `card-surface` utility, so its outline and radius match Card in both light and dark mode.
TSImport
import {
  ImageCarousel,
  type ImageCarouselImage,
} from "@/components/ui/image-carousel";
TSExample
"use client";

import { ImageCarousel } from "@/components/ui/image-carousel";

export function Example() {
  return (
    <ImageCarousel
      images={[
        { src: "/hero-1.jpg", alt: "Hero one", caption: "Opening frame" },
        { src: "/hero-2.jpg", alt: "Hero two", caption: "Second frame" },
      ]}
      aspectRatio="16/9"
      counter
    />
  );
}
Composition
Anatomy of the ImageCarousel.
ImageCarousel                    (single component — pass everything as props)
├── images={[{ src, alt?, caption? }]}
├── frame                        (card-surface: same outline + radius as Card,
│                                 light and dark, with overflow clipped)
│   ├── slide                    (aspectRatio-boxed <img>, object-cover)
│   ├── counter                  (optional "1 / 4" chip, top-right)
│   ├── arrows                   (optional prev/next scrim buttons, inset)
│   └── dots                     (optional pill of indicators, bottom-center)
├── caption                      (active slide's caption, under the frame)
└── thumbnails                   (optional strip under the frame)
Default
One image per view with inset arrows, a counter chip, a dots pill inside the frame, and the active slide's caption underneath.
Modern layout
Classic layout
Bold layout
Editorial layout
1 / 4

Modern — bold type on an asymmetric grid

Thumbnails
A thumbnail strip under the frame, with the dots pill turned off. The strip scrolls horizontally and carries `scroll-fade-x`; the active thumb takes the focus ring.
Modern layout
Classic layout
Bold layout
Editorial layout
1 / 4

Modern — bold type on an asymmetric grid

Three per view
`slidesPerView={3}` with a 4:3 frame — a contact-sheet rail that collapses to one column on mobile.
Modern layout
Classic layout
Bold layout
Editorial layout

Modern — bold type on an asymmetric grid

Autoplay + loop
Advances every 3 seconds and wraps past the last image. Arrows stay live so a viewer can take over.
Modern layout
Classic layout
Bold layout
Editorial layout

Modern — bold type on an asymmetric grid

API Reference
Props exposed by the ImageCarousel component.
PropTypeDefaultDescription
imagesImageCarouselImage[]Slides to render. Each is `{ src, alt?, caption? }`. `alt` falls back to `caption`, then to an index label.
aspectRatiostring"16/9"CSS aspect ratio for the frame, e.g. `"4/3"` or `"1/1"`. Images fill it with `object-cover`.
slidesPerView1 | 2 | 31Slides visible at once. `2` and `3` collapse to one column on small screens.
loopbooleanfalseWrap from the last image back to the first.
autoPlayIntervalnumber0Advance automatically every N milliseconds. `0` (default) disables autoplay.
arrowsbooleantruePrev/next buttons inset into the frame, on their own dark scrim so they stay legible over any photo. Hidden when every slide is already visible; each fades out when it can no longer scroll.
dotsbooleantrueIndicator dots in a translucent pill pinned to the bottom-center of the frame.
thumbnailsbooleanfalseScrollable thumbnail strip under the frame (carries `scroll-fade-x`).
counterbooleanfalsePins a "1 / 4" chip to the frame's top-right corner.
onIndexChange(index: number) => voidFired whenever the active slide changes.
classNamestringExtends the outer wrapper (the frame keeps its Card outline).