Shoji

Dynamic mode, video, and events

A hand-built items array (no DOM scanning at all — dynamic mode), including three video items (HTML5, YouTube, Vimeo), with click-to-open wired by hand (dynamic mode has no scanned elements to attach listeners to automatically). Every core lifecycle event is logged live below as it fires.

Shoji not yet initialized.

Event log

Code

The items array — three plain image items, then three video items:

const gallery = new Shoji('#gallery', {
  items: [
    // width/height: the original's real pixel size — required (not just
    // preferred) for the open animation and open-transition placeholder to
    // show at all. See the Getting started guide's GalleryItem fields table.
    { id: 'p1', src: 'photo-1.jpg', width: 1600, height: 1200, caption: 'Sunset over the bay' },
    { id: 'p2', src: 'photo-2.jpg', width: 1600, height: 1200, caption: 'Mountain trail' },
    { id: 'p3', src: 'photo-3.jpg', width: 1600, height: 1200, caption: 'City lights' },
    {
      id: 'v1',
      src: 'clip.mp4',
      video: { provider: 'html5' },
      // One entry per format alternative — the browser plays the first it
      // can decode, same as native <video><source> markup.
      sources: [
        { src: 'clip.webm', type: 'video/webm' },
        { src: 'clip.mp4', type: 'video/mp4' },
      ],
      poster: 'clip-poster.jpg',
      width: 1600,
      height: 1200,
      caption: 'Sample video',
    },
    {
      // video: true — dynamic-mode-only shorthand, infers the whole
      // descriptor from src (youtube or vimeo if the host matches, html5
      // otherwise). No provider, no id to type by hand.
      id: 'v2',
      src: 'https://www.youtube.com/watch?v=BB49x_uMlGA',
      video: true,
      poster: 'yt-poster.jpg',
      width: 1600,
      height: 1200,
      caption: 'YouTube via video: true',
    },
    {
      id: 'v3',
      src: 'https://vimeo.com/112787180',
      video: true,
      poster: 'vimeo-poster.jpg',
      width: 1280,
      height: 534,
      caption: 'Vimeo via video: true',
    },
  ],
  plugins: [Shoji.Video, Shoji.Autoplay], // Video: renders the youtube item; Autoplay: the slideshow
  // autoStart: true begins the slideshow the moment the gallery opens,
  // instead of waiting for a click on the toolbar button/Space. Arriving
  // at a video slide plays it and advances on 'ended' instead of the
  // fixed interval — see the Settings guide's Autoplay section.
  autoplay: { autoStart: true, interval: 4000 },
});

// Dynamic mode has no scanned DOM to wire clicks from — the host owns
// the thumbnail markup, so the host wires the click too:
document.querySelectorAll('#gallery > a').forEach((el, i) => {
  el.addEventListener('click', () => gallery.open(i));
});

Prefer to be explicit about the provider but still skip typing the id by hand? Same result, just spelled out — and this form also works in selector mode via data-shoji-video alone:

{ id: 'v2', src: 'https://www.youtube.com/watch?v=BB49x_uMlGA', video: { provider: 'youtube' } }
// → resolved to { provider: 'youtube', id: 'BB49x_uMlGA' } automatically, same as video: true above

Every core lifecycle event, logged as it fires:

[
  'beforeOpen', 'open', 'afterOpen',
  'beforeSlide', 'afterSlide', 'slideItemLoad',
  'itemsUpdated',
  'beforeClose', 'close', 'afterClose',
  'destroy',
].forEach((name) => gallery.on(name, (detail) => console.log(name, detail)));

updateSlides() — diffs by id (falling back to src) and re-renders, firing itemsUpdated above:

gallery.updateSlides([
  ...gallery.items,
  { id: 'p4', src: 'photo-4.jpg', width: 1600, height: 1200, caption: 'Photo 4' },
]);