Demos

Vue image gallery component

@lightgallery/vue is a native Vue 3 image gallery: every node is rendered by Vue, with v-model for the open state and the index, typed emits, scoped slots and a Teleport overlay. Animated thumbnails, pinch and double-tap zoom, captions, rotate, fullscreen and sharing come as tree-shakable plugins. The full component API is in the Vue package docs.

Demo

Click any thumbnail. The Vue component renders the same markup and runs the same gallery logic, the shared headless core guarantees identical behavior across all four packages.

Install
npm install @lightgallery/vue lightgallery

Peer range is vue >=3.4 (the component uses defineModel). The CSS ships from the lightgallery package and is shared by every binding, import it globally, in main.ts or your root stylesheet:

import 'lightgallery/css/lightgallery.css';
import 'lightgallery/css/lg-thumbnail.css';
import 'lightgallery/css/lg-zoom.css';
Thumbnail grid

Wrap each trigger in <LgItem>. Mount order is slide order, and clicking a trigger opens the lightbox on that slide:

<script setup lang="ts">
import { LightGallery, LgItem, type LgGalleryItem } from '@lightgallery/vue';
import Thumbnail from '@lightgallery/vue/plugins/thumbnail';
import Zoom from '@lightgallery/vue/plugins/zoom';

const plugins = [Thumbnail, Zoom];

const items: LgGalleryItem[] = [
    {
        src: 'img/1-1600.jpg',
        thumb: 'img/1-240.jpg',
        alt: 'Mountains',
        // enables the zoom-from-origin open animation
        lgSize: '1600-1067',
        caption: 'Mountains',
    },
    {
        src: 'img/2-1600.jpg',
        thumb: 'img/2-240.jpg',
        alt: 'Forest path',
        lgSize: '1600-2400',
        caption: 'Forest path',
    },
];
</script>

<template>
    <LightGallery :plugins="plugins" :zoom="{ scale: 1.5 }">
        <LgItem v-for="item of items" :key="item.src" :item="item">
            <img :src="item.thumb" :alt="item.alt" />
        </LgItem>
    </LightGallery>
</template>
Settings, plugins and events

Core settings are same-named props (:mode, :speed, :loop, :caption-position, …). Each plugin adds one settings prop named after it, and events are kebab-case emits with no on prefix:

<LightGallery
    :plugins="[Thumbnail, Zoom]"
    :speed="400"
    :thumbnail="{ animateThumb: true, thumbWidth: 130 }"
    :zoom="{ scale: 1.5, actualSize: true }"
    @after-slide="({ index }) => console.log(index)"
/>

Adding a plugin to :plugins is what enables it, a bare :thumbnail prop only configures one that is already loaded.

Controlled and imperative

v-model:open and v-model:index hand you the state; a template ref exposes the same actions the other packages have:

<script setup>
import { ref } from 'vue';
import { LightGallery } from '@lightgallery/vue';

const open = ref(false);
const index = ref(0);
const lg = ref();
</script>

<template>
    <button @click="open = true">Open gallery</button>
    <button @click="lg.openGallery(2)">Open at slide 3</button>

    <LightGallery
        ref="lg"
        :slides="items"
        v-model:open="open"
        v-model:index="index"
    />
</template>

The handle covers openGallery(index?), closeGallery(), goToSlide(i), nextSlide(), prevSlide() and refresh().

Slots

Captions, the counter and the navigation buttons are named scoped slots, #caption, #counter, #prev-button, #next-button, so you render them with your own components instead of HTML strings:

<LightGallery :slides="items">
    <template #caption="{ item }">
        <h4>{{ item.alt }}</h4>
    </template>
</LightGallery>
Nuxt and SSR

Every entry imports without browser globals, and the overlay never server-renders, the <Teleport> mounts on the client, so there is no hydration mismatch and no <ClientOnly> wrapper needed. Your trigger markup still server-renders, so the grid stays crawlable. Import the CSS through nuxt.config:

export default defineNuxtConfig({
    css: ['lightgallery/css/lightgallery.css'],
});

More in the Vue package docs, the full prop surface, all 14 plugins plus the justified grid, and the accessibility behavior. See also the Vue video gallery demo.

Edit this page on GitHub