Shoji API Reference
    Preparing search index...

    Interface GalleryOptions

    interface GalleryOptions {
        selector?: string;
        items?: GalleryItemInput[];
        index?: number;
        openOnInit?: boolean;
        locale?: Record<string, string>;
        plugins?: ShojiPlugin[];
        autoHideDelay?: number | false;
        maxPinnedToolbarButtons?: number;
        preload?: number;
        counter?: boolean;
        showVideoCaption?: boolean;
        loop?: boolean;
        closable?: boolean;
        backdropOpacity?: number;
        gestures?: Partial<GestureEngineOptions>;
        mode?: string;
        transitionDuration?: number;
        [key: string]: unknown;
    }

    Indexable

    • [key: string]: unknown
    Index
    selector?: string

    DOM selector for gallery items when not using dynamic mode.

    items?: GalleryItemInput[]

    Dynamic-mode item list; mutate live via gallery.updateSlides().

    index?: number

    Index to open on — used both as open()'s default argument and, with openOnInit, as the index opened automatically at construction.

    openOnInit?: boolean

    Opens the lightbox immediately at construction (to index, default 0), instead of the normal default of staying closed until the host calls open() or a scanned/layout-rendered thumbnail is clicked. Default false. Useful for hash/deep-link-style integrations that should land straight in the lightbox; everyone else should leave this off — a gallery that pops open on page load without a click is rarely what's wanted.

    locale?: Record<string, string>

    Flat locale key map — see CLAUDE.md: no hardcoded English in UI.

    plugins?: ShojiPlugin[]

    Registered plugins; each plugin's own options nest under options[plugin.name].

    autoHideDelay?: number | false

    DESIGN.md §2.8 — ms of inactivity before all buttons/overlays (toolbar, prev/next, counter, caption) auto-hide; default 5000. 0 does not turn auto-hide off — it does the opposite: controls are hidden immediately on open and stay hidden permanently, regardless of activity. false is the actual "always visible" value: the idle timer never arms at all, so controls just stay shown, same as if activity kept resetting it forever (other explicit hides — hideControls(), drag-to-close's own live cue — are unrelated to this option and still work regardless).

    maxPinnedToolbarButtons?: number

    DESIGN.md §3.1a — the most ctx.ui.toolbar('right', ...)-registered plugin buttons (in registration order) that stay pinned directly on the toolbar row once it overflows; default 2. A ceiling, not a guarantee — if pinning even this many would still wrap the row (e.g. a wide counter or other left-slot content leaves less room than usual), more collapse into the popover until it fits, down to zero if it must; the counter and closeButton are never allowed to wrap. The rest collapse into the overflow popover, latest-registered first. closeButton and the overflow caret itself are never counted against this — they're always on the row regardless.

    preload?: number

    DESIGN.md §2.3 — how many slides on each side of the active one are kept mounted and proactively decoded ahead of time; default 1. Navigating to any index within that window shows instantly, no loading spinner — its content was already decoded and cached (by item index, surviving the pool's internal slot reshuffling) before you got there. Navigating further than preload away (a fast flick through several slides, or a direct goTo()/deep link) still shows the spinner while that one decodes, same as ever — this only changes what counts as "already ready."

    counter?: boolean

    Shows the "N / M" counter badge; default true. Purely visual — the live-region announcement (§2.6) always includes position regardless.

    showVideoCaption?: boolean

    DESIGN.md §2.3a — starts a video slide's caption shown instead of hidden; default false. No effect on a photo's caption.

    loop?: boolean

    DESIGN.md §2.2 — next()/prev() (and the arrow-key/toolbar-button paths that call them) wrap past the last/first item instead of stopping; default true. Does not affect goTo(index) with an explicit out-of-range index (still clamps — a directed jump, not a step) or Home/End (still an absolute jump to the first/last item).

    closable?: boolean

    Default true. false disables every viewer-facing way to close the lightbox: the close button (hidden entirely, not just inert), clicking the backdrop, Escape, and vertical swipe-to-close (no live drag feedback either, not just a release that fails to close). For non-closable embeds — a gallery meant to stay open permanently once shown. gallery.close() itself is unaffected — this only gates the four built-in viewer-triggered paths, host code can still close it programmatically at any time.

    backdropOpacity?: number

    The backdrop's real, honest opacity — 0 fully transparent, 1 fully opaque (solid --shoji-color-backdrop, shoji.css, itself a fully opaque hue by default), without needing to know or override the full color value. Clamped to [0, 1]. Unset (the default) leaves the CSS custom property --shoji-backdrop-opacity (default 0.92 dark / 0.96 light, matching this theme's pre-existing look) untouched, so a host already themeing it directly in CSS is unaffected either way.

    gestures?: Partial<GestureEngineOptions>

    DESIGN.md §2.4 — overrides the gesture engine's lockThreshold/ swipeThreshold/swipeVelocity (defaults: 10px, 50px, 0.3px/ms). Partial: any field left out keeps its default. Momentum easing is not configurable here — it's the CSS custom property --shoji-momentum-easing, per CLAUDE.md's "no hardcoded sizes/timings in JS, everything through --shoji-* custom properties."

    mode?: string

    DESIGN.md §2.5 — the slide-to-slide transition for programmatic navigation (buttons, keyboard, autoplay, goTo()); never affects a gesture-driven swipe, which always uses its own live-drag/settle animation regardless of mode (§2.4). Default 'slide'. One of the built-in preset names (slide, fade, zoom, deck, slideVertical, push, fadeUp, fadeDown, fadeLeft, fadeRight, zoomOut, scaleUp, scaleDown, rotate, rotateLeft, rotateRight, flipX, flipY, cube, coverflow, drop) — or any other string, treated as a custom CSS class pair (shoji-transition-<mode>-enter/-leave) the host supplies its own transition/@keyframes animation for; no JS needed on the host's end.

    transitionDuration?: number

    DESIGN.md §2.5 — milliseconds for mode's transition, plus open/close zoom and Layout's own FLIP reflow (they all key off the same --shoji-duration). Default 300, matching --shoji-duration's own CSS default — this option doesn't move timing into JS, it's a convenience that sets that same CSS custom property for you, the same way backdropOpacity sets --shoji-backdrop-opacity. Unset leaves --shoji-duration (and prefers-reduced-motion's own 0ms override of it) untouched, so a host already theming it directly in CSS is unaffected either way. Clamped to a minimum of 0.