Vai al contenuto

Componente

Thumbnav

Una fila di miniature per scegliere un'immagine: link ad ancora verso le slide di un carosello, con la miniatura corrente evidenziata durante lo scorrimento.

Riferimento
<it-thumbnav>
Classi
ita-thumbnavita-thumbnav-smita-thumbnav-lgita-thumbnav-verticalita-thumbnav-spy
Basato su (daisyUI)
carouselcarousel-item
Solo CSS
Ogni miniatura è un link alla sua slide (#galleria-3): il browser scorre il carosello fino all'immagine. La miniatura corrente usa scroll-target-group e :target-current (Chrome 140+), altrimenti aria-current dal server. Il salto dell'ancora può scorrere anche la pagina e aggiorna l'hash: il frammento JavaScript sotto lo evita.
Storybook
Apri le storie di Thumbnav

Esempio base

Mostra il codice HTML
<nav aria-label="Miniature" class="ita-thumbnav">
  <ul>
    <li><a href="#" aria-current="true"><img src="https://picsum.photos/id/1015/200/200" alt="Paesaggio 1" loading="lazy"></a></li>
    <li><a href="#"><img src="https://picsum.photos/id/1016/200/200" alt="Paesaggio 2" loading="lazy"></a></li>
    <li><a href="#"><img src="https://picsum.photos/id/1018/200/200" alt="Paesaggio 3" loading="lazy"></a></li>
    <li><a href="#"><img src="https://picsum.photos/id/1019/200/200" alt="Paesaggio 4" loading="lazy"></a></li>
    <li><a href="#"><img src="https://picsum.photos/id/1020/200/200" alt="Paesaggio 5" loading="lazy"></a></li>
    <li><a href="#"><img src="https://picsum.photos/id/1021/200/200" alt="Paesaggio 6" loading="lazy"></a></li>
    <li><a href="#"><img src="https://picsum.photos/id/1022/200/200" alt="Paesaggio 7" loading="lazy"></a></li>
  </ul>
</nav>

Dimensioni

Mostra il codice HTML
<div class="flex flex-col gap-6">
<nav aria-label="Miniature piccole" class="ita-thumbnav ita-thumbnav-sm">
  <ul>
    <li><a href="#" aria-current="true"><img src="https://picsum.photos/id/1015/200/200" alt="Paesaggio 1" loading="lazy"></a></li>
    <li><a href="#"><img src="https://picsum.photos/id/1016/200/200" alt="Paesaggio 2" loading="lazy"></a></li>
    <li><a href="#"><img src="https://picsum.photos/id/1018/200/200" alt="Paesaggio 3" loading="lazy"></a></li>
    <li><a href="#"><img src="https://picsum.photos/id/1019/200/200" alt="Paesaggio 4" loading="lazy"></a></li>
    <li><a href="#"><img src="https://picsum.photos/id/1020/200/200" alt="Paesaggio 5" loading="lazy"></a></li>
    <li><a href="#"><img src="https://picsum.photos/id/1021/200/200" alt="Paesaggio 6" loading="lazy"></a></li>
    <li><a href="#"><img src="https://picsum.photos/id/1022/200/200" alt="Paesaggio 7" loading="lazy"></a></li>
  </ul>
</nav>
<nav aria-label="Miniature grandi" class="ita-thumbnav ita-thumbnav-lg">
  <ul>
    <li><a href="#" aria-current="true"><img src="https://picsum.photos/id/1015/200/200" alt="Paesaggio 1" loading="lazy"></a></li>
    <li><a href="#"><img src="https://picsum.photos/id/1016/200/200" alt="Paesaggio 2" loading="lazy"></a></li>
    <li><a href="#"><img src="https://picsum.photos/id/1018/200/200" alt="Paesaggio 3" loading="lazy"></a></li>
    <li><a href="#"><img src="https://picsum.photos/id/1019/200/200" alt="Paesaggio 4" loading="lazy"></a></li>
    <li><a href="#"><img src="https://picsum.photos/id/1020/200/200" alt="Paesaggio 5" loading="lazy"></a></li>
  </ul>
</nav>
</div>

Verticale

Mostra il codice HTML
<nav aria-label="Miniature" class="ita-thumbnav ita-thumbnav-vertical">
  <ul>
    <li><a href="#" aria-current="true"><img src="https://picsum.photos/id/1015/200/200" alt="Paesaggio 1" loading="lazy"></a></li>
    <li><a href="#"><img src="https://picsum.photos/id/1016/200/200" alt="Paesaggio 2" loading="lazy"></a></li>
    <li><a href="#"><img src="https://picsum.photos/id/1018/200/200" alt="Paesaggio 3" loading="lazy"></a></li>
    <li><a href="#"><img src="https://picsum.photos/id/1019/200/200" alt="Paesaggio 4" loading="lazy"></a></li>
    <li><a href="#"><img src="https://picsum.photos/id/1020/200/200" alt="Paesaggio 5" loading="lazy"></a></li>
  </ul>
</nav>

Con un carosello

Clicca una miniatura: il carosello va all'immagine e la miniatura si evidenzia mentre scorri.

Mostra il codice HTML
<div class="flex flex-col gap-4">
<section class="ita-carousel ita-carousel-image" aria-roledescription="carosello" aria-label="Galleria">
  <div>
    <div class="carousel" tabindex="0">
    <figure id="galleria-1" role="group" aria-roledescription="slide" aria-label="1 di 7" class="carousel-item">
      <img src="https://picsum.photos/id/1015/1200/675" alt="Paesaggio 1" loading="lazy">
      <figcaption class="ita-carousel-caption">
        <p>Paesaggio 1</p>
      </figcaption>
    </figure>
    <figure id="galleria-2" role="group" aria-roledescription="slide" aria-label="2 di 7" class="carousel-item">
      <img src="https://picsum.photos/id/1016/1200/675" alt="Paesaggio 2" loading="lazy">
      <figcaption class="ita-carousel-caption">
        <p>Paesaggio 2</p>
      </figcaption>
    </figure>
    <figure id="galleria-3" role="group" aria-roledescription="slide" aria-label="3 di 7" class="carousel-item">
      <img src="https://picsum.photos/id/1018/1200/675" alt="Paesaggio 3" loading="lazy">
      <figcaption class="ita-carousel-caption">
        <p>Paesaggio 3</p>
      </figcaption>
    </figure>
    <figure id="galleria-4" role="group" aria-roledescription="slide" aria-label="4 di 7" class="carousel-item">
      <img src="https://picsum.photos/id/1019/1200/675" alt="Paesaggio 4" loading="lazy">
      <figcaption class="ita-carousel-caption">
        <p>Paesaggio 4</p>
      </figcaption>
    </figure>
    <figure id="galleria-5" role="group" aria-roledescription="slide" aria-label="5 di 7" class="carousel-item">
      <img src="https://picsum.photos/id/1020/1200/675" alt="Paesaggio 5" loading="lazy">
      <figcaption class="ita-carousel-caption">
        <p>Paesaggio 5</p>
      </figcaption>
    </figure>
    <figure id="galleria-6" role="group" aria-roledescription="slide" aria-label="6 di 7" class="carousel-item">
      <img src="https://picsum.photos/id/1021/1200/675" alt="Paesaggio 6" loading="lazy">
      <figcaption class="ita-carousel-caption">
        <p>Paesaggio 6</p>
      </figcaption>
    </figure>
    <figure id="galleria-7" role="group" aria-roledescription="slide" aria-label="7 di 7" class="carousel-item">
      <img src="https://picsum.photos/id/1022/1200/675" alt="Paesaggio 7" loading="lazy">
      <figcaption class="ita-carousel-caption">
        <p>Paesaggio 7</p>
      </figcaption>
    </figure>
    </div>
  </div>
</section>
<nav aria-label="Scegli l'immagine" class="ita-thumbnav ita-thumbnav-spy">
  <ul>
    <li><a href="#galleria-1"><img src="https://picsum.photos/id/1015/200/200" alt="Paesaggio 1" loading="lazy"></a></li>
    <li><a href="#galleria-2"><img src="https://picsum.photos/id/1016/200/200" alt="Paesaggio 2" loading="lazy"></a></li>
    <li><a href="#galleria-3"><img src="https://picsum.photos/id/1018/200/200" alt="Paesaggio 3" loading="lazy"></a></li>
    <li><a href="#galleria-4"><img src="https://picsum.photos/id/1019/200/200" alt="Paesaggio 4" loading="lazy"></a></li>
    <li><a href="#galleria-5"><img src="https://picsum.photos/id/1020/200/200" alt="Paesaggio 5" loading="lazy"></a></li>
    <li><a href="#galleria-6"><img src="https://picsum.photos/id/1021/200/200" alt="Paesaggio 6" loading="lazy"></a></li>
    <li><a href="#galleria-7"><img src="https://picsum.photos/id/1022/200/200" alt="Paesaggio 7" loading="lazy"></a></li>
  </ul>
</nav>
</div>

Con JavaScript (opzionale)

La ricetta è solo CSS e funziona così com'è. Questi frammenti non sono inclusi nel pacchetto: mostrano come aggiungere il comportamento che richiede uno script, in JavaScript semplice o in React.

Miniatura corrente in tutti i browserjs

Aggiorna aria-current con IntersectionObserver e scorre il carosello senza muovere la pagina.

// Keep aria-current on the thumbnail of the visible slide (all browsers),
// and scroll the carousel without moving the page when a thumbnail is clicked.
document.querySelectorAll("nav[aria-label] ul").forEach((list) => {
  const links = [...list.querySelectorAll("a[href^='#']")];
  const slides = links.map((a) => document.querySelector(a.hash)).filter(Boolean);
  if (!slides.length) return;

  const io = new IntersectionObserver((entries) => {
    for (const e of entries) {
      if (e.intersectionRatio < 0.6) continue;
      for (const a of links) {
        if (a.hash === "#" + e.target.id) a.setAttribute("aria-current", "true");
        else a.removeAttribute("aria-current");
      }
    }
  }, { threshold: 0.6 });
  slides.forEach((s) => io.observe(s));

  list.addEventListener("click", (ev) => {
    const a = ev.target.closest("a[href^='#']");
    if (!a) return;
    ev.preventDefault();
    document.querySelector(a.hash)?.scrollIntoView({ behavior: "smooth", block: "nearest", inline: "start" });
  });
});

Galleria in Reacttsx

import { useRef, useState } from "react";

type Photo = { src: string; thumb: string; alt: string };

/** Gallery with thumbnails: React owns the current index. */
export function Gallery({ photos }: { photos: Photo[] }) {
  const [current, setCurrent] = useState(0);
  const track = useRef<HTMLDivElement>(null);
  const show = (i: number) => {
    setCurrent(i);
    track.current?.children[i]?.scrollIntoView({ behavior: "smooth", block: "nearest", inline: "start" });
  };
  return (
    <div className="flex flex-col gap-4">
      <div ref={track} className="carousel w-full gap-4 rounded-box" tabIndex={0}
           onScroll={(e) => setCurrent(Math.round(e.currentTarget.scrollLeft / e.currentTarget.clientWidth))}>
        {photos.map((p) => (
          <img key={p.src} src={p.src} alt={p.alt} className="carousel-item aspect-video w-full object-cover" />
        ))}
      </div>
      <nav aria-label="Scegli l'immagine" className="ita-thumbnav">
        <ul>
          {photos.map((p, i) => (
            <li key={p.thumb}>
              <button type="button" onClick={() => show(i)} aria-current={i === current || undefined}>
                <img src={p.thumb} alt={p.alt} />
              </button>
            </li>
          ))}
        </ul>
      </nav>
    </div>
  );
}