Gallery✨ Premium

Thumbnail Slider

A large view and a row of thumbnail buttons: a click, Enter or a drag on the image slides the view, and the active thumbnail gets a white frame.

JSThumbnailsGallery

Updated

This effect is part of Effect.Labs — 840 vanilla effects, some free, some premium. Gallery has 44 effects, including 6 free. Explore the category →

3 usage examples

Choosing the cover of a wedding invitation — Thumbnail Slider example 1

① Choosing the cover of a wedding invitation

WhenOn the Papyrelle stationery configurator, the invitation preview fills the left column with four thumbnails (foliage, arch, sun, tide) below it; on the right, format, paper and the price for 50 copies. Clicking a thumbnail slides the preview to that design.
WhyThe thumbnail works as a choice button and the large view as proof: designs are compared without leaving the page or opening a window. The frame around the active thumbnail reminds which cover is selected.
Settings--tsl-ratio: 280/176, 52 × 36 px thumbnails (--tsl-thumb-w, --tsl-thumb-h), four <img> (SVG illustrations) in the slides and thumbnails. Active frame turned brown and thumbnail background beige by the scene CSS. The capture clicks the 3rd thumbnail.
Chapters of an online video course — Thumbnail Slider example 2

② Chapters of an online video course

WhenOn the Cursivane platform, the "Typography for the web" module shows the current chapter in a large frame with its title, and the five chapters as thumbnails below, each with its length. On the right: progress, module length, exercise. Clicking a thumbnail changes the chapter shown.
WhyThe thumbnails become a visual table of contents: you see at a glance how many chapters are left and jump straight to the one you want to watch again.
Settings--tsl-ratio: 368/188, 68 × 40 px thumbnails aligned left, length shown over each thumbnail (the button's HTML content), lavender active frame. In a real course each slide would hold the clickable video preview.
A school trip album on a phone — Thumbnail Slider example 3

③ A school trip album on a phone

WhenIn the Haubrines school parents' area, on mobile: the museum trip photo fills the screen width, the five thumbnails line up below and a "Download all" button closes the screen. Parents swipe the photo with their thumb; the active thumbnail moves along.
WhyOn a phone, swiping is the natural gesture to browse photos; thumbnails stay useful to jump straight to an image and see where you are in the album.
Settings--tsl-ratio: 1 (square photo), 26 px thumbnails with a 4 px gap, amber active frame. The capture replays the gesture every 1.1 s by sending the real code a touch pointerdown then a pointerup about 115 px further left; the sliding dot is a marker drawn by the scene.

How it works

Inside .fx-0165-root, the .tsl-slider block stacks a .tsl-viewport window (2/1 format by default, rounded corners) and a .tsl-thumbs row. The window holds a .tsl-track where each .tsl-slide takes the full width; showing slide n means shifting the track by translateX(-n × 100%) in 0.5 s.

Each thumbnail is a real <button>: the n-th thumbnail shows the n-th slide (order makes the link, no index to write). The active thumbnail carries aria-current="true", which gives it full opacity and the white frame; the others stay at 50%. On the large view, a horizontal drag of more than 50 px with a finger or the mouse moves to the next or previous slide, looping, and the thumbnail follows.

Buyers' images go straight in: an <img> in a slide or a thumbnail covers it entirely (object-fit: cover). Without images, the five demo gradients show. The script handles each .fx-0165-root on the page separately: several galleries live side by side without interfering.

Accessibility

  • Reachable thumbnails: native buttons, so Tab, Enter and Space work; each has a name ("Show slide 2") and the current one is flagged with aria-current. White :focus-visible outline.
  • Carousel roles: a named aria-roledescription="carousel" region; slides are role="group" announced as "2 of 5". The track is aria-live="polite": the chosen slide is read out.
  • Hidden slides: inert, so a link or button inside an image that isn't shown cannot take focus.
  • Reduced motion: under prefers-reduced-motion: reduce the view changes without gliding; nothing else moves on its own.
  • Touch: Pointer Events and touch-action: pan-y on the large view: a horizontal gesture changes photo, a vertical one scrolls the page.

Browser compatibility

Dependency-free JavaScript (Pointer Events, aria-current as a styling hook), aspect-ratio (Chrome 88, Firefox 89, Safari 15) and inert (Chrome 102, Firefox 112, Safari 15.5 according to MDN). Measured in Chromium 151, Firefox 153 and WebKit 26.5 (Playwright): two galleries with only the second one driven, thumbnails by keyboard, reduced motion, 390 px without overflow, finger swipe (Chromium) without blocking vertical scrolling, 0 errors.

Chrome 102+✓ Full (measured)
Firefox 112+✓ Full (measured)
Safari 15.5+✓ Full (measured in WebKit)
Edge 102+✓ Full (Chromium engine)
Mobile iOS 15.5+✓ WebKit engine, not checked on a device
Android Chrome 102+✓ Full (touch measured)

Without JavaScript, the first image and the thumbnails show but the thumbnails do nothing. Without aspect-ratio (2020 browsers), the large view has no height: give it a fixed one.

The code

HTML structure to paste into your page (the CSS + JS come with your purchase):

index.html — structure
<div class="fx-0165-root">
  <div class="tsl-slider" role="region" aria-roledescription="carousel" aria-label="…">
    <div class="tsl-viewport">
      <div class="tsl-track" aria-live="polite">
        <div class="tsl-slide" role="group" aria-roledescription="slide" aria-label="1 of 5"><img src="…" alt="…"></div>
        …
      </div>
    </div>
    <div class="tsl-thumbs">
      <button class="tsl-thumb" type="button" aria-label="…" aria-current="true"><img src="…" alt=""></button>
      <button class="tsl-thumb" type="button" aria-label="…"><img src="…" alt=""></button>
      …
    </div>
  </div>
</div>

One-time payment, no subscription — the code is yours forever

Customize

Options passed to the API or data-* attributes:

Option / propertyDefaultEffect
Maximum width (CSS — --tsl-max-width) 640px The gallery takes its container's width up to this limit; none for the full width.
Large view proportions (CSS — --tsl-ratio) 2 / 1 Width/height ratio of the window. Images are cropped to fill it.
Thumbnail size (CSS — --tsl-thumb-w / --tsl-thumb-h) 50px / 32px Width and height of each thumbnail button. The row wraps when it runs out of room.
Images (HTML — <img> in .tsl-slide and .tsl-thumb) none: 5 gradients "Slide 1" to "Slide 5" One image per slide and its smaller version in the thumbnail of the same rank. Keep as many thumbnails as slides.
Thumbnail names (HTML — aria-label of .tsl-thumb) "Show slide 1"… Text read by screen readers; describe what the image shows ("Arch cover").
Active thumbnail (CSS — .tsl-thumb[aria-current="true"]) opacity 1, 2 px #fff frame Change the frame colour or the opacity of inactive thumbnails (0.5 by default).

FAQ

By their rank: the 3rd thumbnail in .tsl-thumbs shows the 3rd .tsl-slide. To reorder, move the slide and its thumbnail together.
Yes, a slide accepts any HTML, including <video>. Hidden slides are inert, but a playing video keeps playing: pause it yourself if you change slide during playback.
Yes: dragging more than 50 px horizontally on the large view, left button held, changes slide. Images don't start a drag-and-drop and text isn't selected during the gesture.