VpvImageGallery Usage
This component creates interactive image galleries with lightbox functionality using PhotoSwipe. It supports multiple layout options and can filter images from your gallery data by folders, specific files, or direct URLs.
You can also see the following pages for detailed examples:
- Gallery Simple Grid Layout: Displays the simple grid layout, along with a number of examples with that layout
- Gallery Masonry Layout: Displays the masonry layout.
- Gallery Full Size Layout: Displays the full-size layout.
- Gallery Filtering: Examples of filtering a large gallery
Setup
Do initial installation first
Before you follow any of the guides below, you should import and install this project in your VitePress site.
You are free to create files and directories wherever you want. However, you will need to update the paths accordingly.
- Create a directory in your project for gallery images, ideally in the
publicdirectory. For example,docs/public/gallery.- You can organize your images in subdirectories, such as
docs/public/gallery/nature,docs/public/gallery/urban, etc.
- You can organize your images in subdirectories, such as
- Create a
gallery.data.jsfile, such as atdocs/.vitepress/theme/data/gallery.data.js.
Copy the following code into your gallery.data.js file
import fs from 'fs';
import path from 'path';
/*
This is a VitePress data loader that scans the public/gallery folder for images.
You will need to set three constants at the top of the file to match your project:
- SITE_DIR: The location of the site (where is the .vitepress folder inside of, ex. 'docs')
- SRC_DIR: The source directory (By default this is '', but if you configured an srcDir value in your VitePress config, you will need to set it here)
- https://vitepress.dev/guide/routing#source-directory
- GALLERY_DIR: The location of the gallery folder
For example, if your project structure looks like this:
- docs/
- .vitepress/
- theme/
- data/
- gallery.data.js
- public/
- gallery/
- image1.jpg
- image2.jpg
- image3.jpg
- index.md
- my-photography.md
You would set the constants like this:
const SITE_DIR = 'docs';
const SRC_DIR = '';
const GALLERY_DIR = 'public/gallery';
*/
const SITE_DIR = 'docs';
const SRC_DIR = '';
const GALLERY_DIR = 'public/gallery';
const absoluteGalleryDir = path.resolve(process.cwd(), SITE_DIR, SRC_DIR, GALLERY_DIR);
const base = process.env.VITEPRESS_BASE || '';
function normalizePath(path) {
return path.replace(/\\/g, '/');
}
function cleanPath(path) {
if (GALLERY_DIR.startsWith('public/')) {
path = path.replace(/^\/public\//, '/');
}
path = path.replace(/\/+/g, '/');
return path;
}
export default {
watch: [`${absoluteGalleryDir}/**/*`],
async load() {
const images = [];
function scanDirectory(dir) {
const items = fs.readdirSync(dir);
items.forEach(item => {
const fullPath = path.join(dir, item);
if (fs.statSync(fullPath).isDirectory()) {
scanDirectory(fullPath);
} else if (/\.(jpg|jpeg|png|gif|webp)$/i.test(item)) {
let relativePath = path.relative(absoluteGalleryDir, fullPath);
relativePath = path.join(GALLERY_DIR, relativePath);
relativePath = `/${normalizePath(relativePath)}`;
relativePath = cleanPath(relativePath);
if (base) {
relativePath = `${base}${relativePath.replace(/^\//, '')}`;
}
images.push({
path: relativePath,
folder: cleanPath(`/${path.dirname(relativePath)}`),
filename: item
});
}
});
}
scanDirectory(absoluteGalleryDir);
return images;
}
};You will need to modify the three variables at the top of the file to match your project:
SITE_DIR: The location of the site (where is the .vitepress folder inside of, ex. 'docs')SRC_DIR: The source directory (By default this is '', but if you configured an srcDir value in your VitePress config, you will need to set it here)GALLERY_DIR: The location of the gallery folder (ex. 'public/gallery')
Import the component and your gallery data in
docs/.vitepress/theme/index.ts(or equivalent)
import { data as galleryData } from './data/gallery.data.js';
// ...
import { VpvImageGallery } from '@cynber/vitepress-valence'
// ...
export default {
enhanceApp({ app, router, siteData }) {
// ...
app.component('VpvImageGallery', VpvImageGallery)
// ...
app.provide('galleryData', galleryData)
}
} satisfies ThemeBasic Usage
Simple Gallery
Display all images from your gallery data:
<VpvImageGallery />Gallery with Specific Folders
Display images from specific folders:
<VpvImageGallery
:folders="['/gallery/nature', '/gallery/urban']"
/>Gallery with Direct URLs
Use direct image URLs instead of gallery data:
<VpvImageGallery
:directUrls="['/images/photo1.jpg', '/images/photo2.jpg']"
/>Gallery Header
Header Configuration
These props allow you to add a header section above the gallery.
headerTitle: The title to display in the header sectionheaderSubtitle: The subtitle to display in the header sectionheaderDate: The date to display in the header sectionheaderLink: A URL to make the header title clickableheaderTitleLines: Limits the number of lines for the header title display (default: 2)headerSubtitleLines: Limits the number of lines for the header subtitle display (default: 1)
Header Date Format
headerDateFormat: Specifies the format of the header date. Can be:"long"(default, example: "October 30, 2025")"short"(example: "Oct 30, 2025")"iso"(example: "2025-10-30")- A custom format string, such as
"yyyy-MM-dd HH:mm"(example: "2025-10-30 17:00")
headerDatePrefix: Text to display before the header date
Kitchen Sink Example for Header Options
<VpvImageGallery
headerTitle="Wedding Photos"
headerSubtitle="Captured by Professional Photography"
:headerTitleLines="1"
:headerSubtitleLines="1"
headerLink="/full-event-album"
headerDate="2024-06-15"
headerDateFormat="long"
headerDatePrefix="Event Date: "
:folders="['/no-images-here']"
/>Legacy Props (Deprecated)
The following props are deprecated but still supported for backwards compatibility. Please use the header* equivalents instead:
title→ useheaderTitletitleLines→ useheaderTitleLinesdate→ useheaderDatedateFormat→ useheaderDateFormatdateTimeDescription→ useheaderDatePrefixlink→ useheaderLinktime→ no longer used
Layout Options
layout
Choose from three layout styles:
"grid"(default) - Square thumbnails in a responsive grid (see example)"full"- Full-width images stacked vertically (see example)"masonry"- Multi-column masonry layout (see example)
Image Filtering
Folder-Based Filtering
folders: Include images from specific folders (array of strings)
<VpvImageGallery
headerTitle="Event Photos"
:folders="['ceremony', 'reception', 'portraits']"
/>Specific Image Selection
images: Include specific image paths (array of strings)
<VpvImageGallery
headerTitle="Featured Photos"
:images="['events/photo1.jpg', 'gallery/highlight.png']"
/>Direct URL Override
directUrls: Use direct URLs instead of gallery data (array of strings)
<VpvImageGallery
headerTitle="External Gallery"
:directUrls="['https://example.com/image1.jpg', '/local/image2.png']"
/>Extension Filtering
includeExtensions: Only include specific file types (array of strings)excludeExtensions: Exclude specific file types (array of strings)
<VpvImageGallery
headerTitle="Photos Only"
:includeExtensions="['jpg', 'jpeg', 'png']"
:excludeExtensions="['gif', 'webp']"
/>Sorting & Organization
forceSort
Manually specify the order of images:
<VpvImageGallery
headerTitle="Ordered Gallery"
:forceSort="['hero-image.jpg', 'second-image.jpg', 'third-image.jpg']"
/>Note: Images not in the forceSort array will appear after the sorted ones in alphabetical order.
Data Source Customization
galleryDataKey
Optional: Override the default export keys
Warning: This section will not be necessary for most users.
While this package has extensive support for filtering gallery folders, you may choose to have completely separate galleries and data loaders for each one.
This can also be helpful if your site is already using the galleryData export for other purposes.
Steps:
- Create any additional gallery folders and data loaders as needed. For example:
docs/public/other-gallerydocs/.vitepress/theme/data/other-gallery.data.js
When creating a new gallery data loader, you will need to update the path accordingly:
// ...
const GALLERY_DIR = 'public/other-gallery';
//...- In your
index.tsfile, import the additional data and/or gallery folders:
import { data as galleryData } from './data/gallery.data.js';
import { data as otherGalleryData } from './data/other-gallery.data.js';
// ...
import { VpvImageGallery } from '@cynber/vitepress-valence'
// ...
export default {
enhanceApp({ app, router, siteData }) {
// ...
app.component('VpvImageGallery', VpvImageGallery)
// ...
app.provide('galleryData', galleryData)
app.provide('otherGalleryData', otherGalleryData)
}
} satisfies Theme- You will need to use the new key (ex.
otherGalleryData) in the components that use the data.
If you overrided the default export keys, you can use this prop to select the correct data. Note that most users will not need to use this prop:
<VpvImageGallery
headerTitle="Custom Gallery"
galleryDataKey="otherGalleryData"
/>