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.
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' },
]);