Skip to content

Image Carousel with Thumbnails

Tailwind CSS image carousel with a clickable thumbnail strip, captions, swipe support, arrow-key navigation and optional looping.

Live preview

Open in new tab

Code

An image carousel with a clickable thumbnail strip, built with Tailwind CSS and dependency-free JavaScript. A large captioned slide sits above a row of small previews, so visitors can jump straight to any image. It suits product galleries, travel stories, portfolios and property listings.

How it works

The root is section.tct-carousel with aria-roledescription="carousel". Inside, the focusable .tct-viewport clips the .tct-track, a flex row of figure.tct-slide elements. Each slide holds an img and a figcaption with a title and short text on a dark gradient. Round previous and next buttons (data-tct-prev, data-tct-next) sit over the stage, a counter shows data-tct-current / data-tct-total, and .tct-thumbs is a horizontally scrollable row of button.tct-thumb elements.

On DOMContentLoaded the script initializes every .tct-carousel. Its goTo() function moves the track with translateX(-100%) steps, marks the matching thumbnail with aria-current="true", makes hidden slides inert, updates the counter and centers the active thumbnail inside the strip with scrollTo, so the page itself never jumps. Clicks on the arrows or thumbnails call goTo(). A keydown listener on the viewport handles ArrowLeft and ArrowRight. Pointer events add swipe and mouse drag: while data-tct-dragging is set the track follows the pointer, and on release it changes slide if the drag passed SWIPE_THRESHOLD, otherwise it snaps back.

style.css adds the eased slide transition, the dimmed inactive thumbnails and the amber outline on the current one.

Customization

  • data-tct-loop on .tct-carousel: set false to stop at the first and last slide; the arrow buttons are then disabled at the ends.
  • SWIPE_THRESHOLD in script.js: lower it for more sensitive swipes, raise it to avoid accidental slide changes.
  • aspect-[4/3] sm:aspect-[16/9] on each .tct-slide: use aspect-square or aspect-[3/2] to match your photos.
  • w-24 sm:w-32 on .tct-thumb: make the previews larger or smaller.
  • outline-color: #fbbf24 in .tct-thumb[aria-current="true"] and the text-amber-400 label: change the accent color.
  • opacity: 0.5 in .tct-thumb: raise it for brighter inactive thumbnails.
  • transition: transform 0.5s in .tct-track: speed up or slow down the slide motion.
  • Replace the placehold.co URLs with your own images, keeping one thumbnail per slide in the same order.

Accessibility

Slides use role="group", aria-roledescription="slide" and labels such as "1 of 5"; inactive slides are inert and aria-hidden. Every thumbnail is a real button with a descriptive aria-label and aria-current on the active one; arrow keys, Home and End move along the strip. The viewport is focusable and responds to arrow keys, and the arrow buttons have sr-only labels. A polite data-tct-status live region announces the slide number and title. All controls show a visible amber focus outline, and transitions are disabled under prefers-reduced-motion: reduce.

Usage notes

Several carousels can share a page because the script scopes all queries to each .tct-carousel; give each copy unique id values.

Requirements

Add these to your page (already included in the download):

  • <script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>

The Tailwind browser build is for prototyping. In production, compile Tailwind with its CLI or your bundler.

Image Carousel with Thumbnails – Tailwind CSS carousels component screenshot
Image Carousel with Thumbnails · Tailwind CSS Carousels

More Carousels

Scroll-Snap Carousel – Pure CSS carousels preview

Scroll-Snap Carousel

Native CSS scroll-snap carousel with arrow buttons, synced pill dots and keyboard support, enhanced by a few lines of vanilla JavaScript.

Carousel with Captions – Bootstrap 5 carousels preview

Carousel with Captions

Bootstrap 5 hero carousel with glass captions, pill indicators, previous and next buttons, a pause control and gradient SVG slides.