@archpublicwebsite/gallery
| Install | |
|---|---|
npm install @archpublicwebsite/gallery |
|
| Latest Version: | 1.0.1 |
| Vue: | 3 |
| License: | MIT |
| Last Updated: | May 5, 2026 |
| Links: | npm |
@archpublicwebsite/gallery
Full-screen image lightbox gallery component for Vue 3 — works in plain Vue, Nuxt, Vuetify, and any other Vue-based framework.
Features
- Fully typed — strict TypeScript interfaces for all props, emits, and composable return values
- FLIP animations — smooth open/close transitions matched to the source image position
- Swiper-powered — swipe, keyboard navigation, fade/slide effect, accessibility module
- Zoom — click or pinch to zoom, configurable max ratio
- Thumbnail strip — responsive breakpoints, active indicator
- Framework-agnostic styling — Tailwind compiled to plain CSS at build time; no Tailwind required by consumers
- SSR compatible — Swiper mounted only after
onMounted; safe for Nuxt - Accessible — ARIA labels, keyboard navigation (
←→),prefers-reduced-motionrespected - Zero peer deps besides Vue — Swiper is bundled; nothing else to install
Installation
npm install @archpublicwebsite/gallery
# or
pnpm add @archpublicwebsite/gallery
# or
yarn add @archpublicwebsite/gallery
Quick Start
<script setup lang="ts">
import type { GalleryImageInput } from "@archpublicwebsite/gallery";
import { ModalGallery, useGallery } from "@archpublicwebsite/gallery";
import '@archpublicwebsite/gallery/style.css';
const images: GalleryImageInput[] = [
{ id: '1', url: 'https://...', alt: 'Pool', caption: 'Infinity Pool' },
{ id: '2', url: 'https://...', alt: 'Lobby', caption: 'Grand Lobby' },
]
const { isOpen, currentIndex, galleryContent, openGallery, closeGallery }
= useGallery(images)
</script>
<template>
<!-- trigger — can be a grid, a single button, anything -->
<img
v-for="(item, i) in galleryContent.items"
:key="item.id"
:src="https://raw.githubusercontent.com/ArchipelagoInternational/archi-ui/HEAD/item.thumbnail || item.url"
:alt="item.alt"
@click="openGallery(i)"
/>
<!-- lightbox -->
<ModalGallery
v-if="isOpen"
:content="galleryContent"
:current-index="currentIndex"
style="position: fixed; inset: 0; z-index: 9999"
@close="closeGallery"
/>
</template>
Framework Examples
Nuxt 3
No plugin needed — import directly in the component.
<script setup lang="ts">
import { ModalGallery, useGallery } from '@archpublicwebsite/gallery';
import '@archpublicwebsite/gallery/style.css';
// ...same as quick start
</script>
Vuetify (inside v-dialog)
<template>
<v-dialog v-model="isOpen" fullscreen>
<ModalGallery
:content="galleryContent"
:current-index="currentIndex"
@close="closeGallery"
/>
</v-dialog>
</template>
React (via any Vue-in-React bridge)
The component is a standard Vue 3 SFC and follows the same composition pattern as @archpublicwebsite/modal and @archpublicwebsite/rangepicker.
useGallery(images) Composable
The composable is the recommended way to manage gallery state. It accepts a static or reactive array of GalleryImageInput objects and returns everything needed to wire up <ModalGallery>.
Input type — GalleryImageInput
| Field | Type | Required | Description |
|---|---|---|---|
id |
string |
✅ | Unique identifier |
url |
string |
✅ | Full-resolution image URL |
thumbnail |
string |
— | Thumbnail URL; derived from url if omitted |
alt |
string |
— | Accessible alt text; falls back to title |
caption |
string |
— | Short label shown in the overlay |
title |
string |
— | Secondary label; used as alt fallback |
description |
string |
— | Longer text shown below caption |
[key: string] |
unknown |
— | Extra API fields are silently ignored |
// TypeScript enforces id + url at compile time
const images: GalleryImageInput[] = [
{ id: '1', url: 'https://...', alt: 'Pool' }, // ✅
{ url: 'https://...' }, // ✗ missing id
{ id: 1, url: "https://..." }, // ✗ id must be string
]
Return value — UseGalleryReturn
| Property | Type | Description |
|---|---|---|
isOpen |
Ref<boolean> |
Whether the lightbox is visible |
currentIndex |
Ref<number> |
Active slide index |
galleryContent |
ComputedRef<GalleryContent> |
Structured data to pass to :content |
openGallery(index?) |
(index?: number) => void |
Open at a given index (default: 0) |
closeGallery() |
() => void |
Close the lightbox |
Reactive images example (fetched from an API):
const { data: rooms } = await useFetch('/api/rooms');
const { isOpen, galleryContent, openGallery, closeGallery } = useGallery(
() =>
rooms.value?.map(r => ({ id: r.id, url: r.image, alt: r.name })) ?? [],
)
<ModalGallery> Props
| Prop | Type | Default | Description |
|---|---|---|---|
content |
GalleryContent |
required | Gallery data — use useGallery() to produce this |
currentIndex |
number |
0 |
Active slide on mount |
lightboxOptions |
LightboxOptions |
see below | Behaviour overrides |
LightboxOptions
| Option | Type | Default | Description |
|---|---|---|---|
showThumbnails |
boolean |
true |
Show thumbnail strip at the bottom |
showNavigation |
boolean |
true |
Show prev/next arrows |
showPagination |
boolean |
true |
Show fraction counter (e.g. "3 / 12") |
showCaption |
boolean |
true |
Show caption and description overlay |
enableZoom |
boolean |
true |
Enable click/pinch to zoom |
thumbnailSize |
'small' | 'medium' | 'large' |
'medium' |
Thumbnail strip size |
effect |
'slide' | 'fade' |
'slide' |
Slide transition effect |
maxZoom |
number |
3 |
Maximum zoom ratio |
All options have TypeScript autocomplete and hover documentation.
// ✗ TypeScript catches this at compile time:
<ModalGallery :lightbox-options="{ thumbnailSize: 'huge' }" />
// ^^^^^^ not assignable to ThumbnailSize
Events
| Event | Payload | Description |
|---|---|---|
close |
— | Fired when the user closes the gallery (close button or animation end) |
image-change |
(index: number, item: GalleryItem) |
Fired when the active slide changes |
<ModalGallery
...
@close="closeGallery"
@image-change="
(index, item) => analytics.track('gallery_view', { id: item.id })
"
/>
Animations
The gallery uses FLIP animations to match the position and size of the source image on open, creating a natural expand-from-thumbnail effect. On close, a ghost image animates back to the original position.
- Detects the source
<img>element in the DOM by matching the URL - Falls back to a simple fade if the source cannot be found
- Respects
prefers-reduced-motion: uses a short opacity fade instead
Auto-hiding Chrome
When content.items has only one image, navigation arrows, pagination, and the thumbnail strip are automatically hidden regardless of lightboxOptions. No extra config needed.
Styling & Theming
The package ships a single compiled CSS file — import it once at the top of your app or in the component:
import '@archpublicwebsite/gallery/style.css';
The gallery uses scoped class names prefixed with arch-gallery- to avoid collisions with Vuetify, Bootstrap, or any other UI framework.
Publishing a new version
cd packages/gallery
pnpm version:patch # 1.0.0 → 1.0.1
pnpm version:minor # 1.0.0 → 1.1.0
pnpm version:major # 1.0.0 → 2.0.0
npm publish
prepublishOnly runs pnpm build automatically before publishing.
Related Packages
A pretty Vue.js component to display an image gallery lightbox inspired by fancy...
Version History
| Version | Released | Vue | License |
|---|---|---|---|
| 1.0.1 | ^3.5.22 | MIT | |
| 1.0.0 | ^3.5.22 | MIT |