# VistaView v2 Documentation - Full
> Generated: 2026-06-26T11:51:13.463Z
> This file contains the complete VistaView documentation in a single document.
> Website: https://vistaview.jujiplay.com
> GitHub: https://github.com/juji/vistaview
> npm: https://www.npmjs.com/package/vistaview
## About VistaView
VistaView is a lightweight, modern image lightbox library for the web. Zero dependencies, and highly customizable.
## Table of Contents
1. [Index](#index)
2. [Core](#core)
3. [Framework Integrations](#framework-integrations)
4. [Extensions](#extensions)
5. [Styling & Theming](#styling--theming)
6. [API Reference](#api-reference)
---
## Index
---
# VistaView
A lightweight, modern image lightbox library for the web. Zero dependencies, and highly customizable.
Path: /index
import CreateGallerySection from '../../components/home/CreateGallerySection.astro';
import ThemeSelection from '../../components/home/ThemeSelection.astro';
import ExtensionsSection from '../../components/home/ExtensionsSection.astro';
---
VistaView is inspired by PhotoSwipe.
Created by juji.
---
## Core
---
# Installation
How to install VistaView in your project
Path: /core/installation

VistaView is a lightweight image lightbox library that can be installed via npm or used directly from a CDN.
## Package Manager Installation
import { Tabs, TabItem } from '@astrojs/starlight/components';
```bash
npm install vistaview
```
```bash
yarn add vistaview
```
```bash
pnpm add vistaview
```
```bash
bun add vistaview
```
## CDN Installation
For quick prototyping or non-bundler environments, use the UMD build via CDN. Use these URLs for the latest published version:
### unpkg
```html
```
### jsDelivr
```html
```
## Bundle Sizes
VistaView is lightweight and optimized for production. Bundle sizes are for v2:
- **Core Library (ESM):** 0.71 KB (0.24 KB gzip)
- **Core Library (UMD):** 40.16 KB (10.73 KB gzip)
- **CSS:** 7.71 KB (1.80 KB gzip)
## Browser Support
VistaView works in all modern browsers:
- Chrome (latest)
- Firefox (latest)
- Safari (latest)
- Edge (latest)
## Framework Integrations
VistaView provides official bindings for popular frameworks. Each integration ships a component (recommended) and a hook/composable for more advanced use cases:
- **[React](/integrations/react)** – `VistaView` component + `useVistaView` hook, exports `VistaViewProps` and `VistaComponentRef` types
- **[Vue 3](/integrations/vue)** – `VistaView` component + `useVistaView` composable, exports `VistaViewProps` and `VistaComponentRef` types
- **[Svelte](/integrations/svelte)** – `VistaView` component + `useVistaView` hook, exports `VistaViewProps` and `VistaComponentRef` types
- **[Solid](/integrations/solid)** – `VistaView` component + `useVistaView` hook, exports `VistaViewProps` type
- **[Vanilla JS](/integrations/vanilla)** – Direct `vistaView()` API, no wrapper needed
All framework packages are imported from the same `vistaview` package using subpath exports:
```ts
import { VistaView, useVistaView } from 'vistaview/react';
import { VistaView, useVistaView } from 'vistaview/vue';
import { VistaView, useVistaView } from 'vistaview/svelte';
import { VistaView, useVistaView } from 'vistaview/solid';
```
## Next Steps
- Follow an [Integration guide](/integrations/react) for your framework
- Explore [configuration options](/core/configuration/complete)
- Learn about [extensions](/extensions/overview)
---
# Lifecycle Functions
Override default lifecycle behavior with custom functions
Path: /core/configuration/advanced
You can override default lifecycle functions to customize behavior at different stages:
```typescript
import {
vistaView,
// lifecycle functions
init,
open,
imageSetup,
transition,
close,
} from 'vistaview';
vistaView({
elements: '#gallery a',
// Custom initialization (runs once on instance creation)
initFunction: (vistaView) => {
console.log('Custom init');
init(vistaView); // Call default init
},
// Custom open behavior (runs when lightbox opens)
openFunction: (vistaView) => {
console.log('Custom open');
open(vistaView); // Call default open
},
// Custom setup when navigating between images
imageSetupFunction: (data, vistaView) => {
console.log('Setting up image:', data.index.to);
imageSetup(data, vistaView); // Call default imageSetup
},
// Custom transition animation
transitionFunction: async (data, abortSignal, vistaView) => {
console.log('Custom transition');
// Use default transition
return transition(data, abortSignal, vistaView);
},
// Custom close behavior (runs when lightbox closes)
closeFunction: (vistaView) => {
console.log('Custom close');
close(vistaView); // Call default close
},
});
```
See the [API Reference](/api-reference/main-function) for more details on these functions.
---
# Animation Options
Configure animation timing and behavior in VistaView
Path: /core/configuration/animation
## animationDurationBase
Base multiplier for all animation timings in VistaView. This unitless value is multiplied to create different animation durations throughout the lightbox.
**How it works:**
- The base value is multiplied by `1ms`, `2ms`, etc. to create proportional timings
- Primary animations (open, close, transitions): `333ms` (1× base)
- Delays and sequential animations: `666ms` (2× base)
- Changing this value scales all animations proportionally, maintaining timing relationships
**Default:** `333`
```typescript
vistaView({
elements: '#gallery a',
animationDurationBase: 333, // default
});
```
## rapidLimit
Defines the time threshold (in milliseconds) for detecting rapid navigation. When users navigate faster than this limit, VistaView skips transition animations for better performance.
**How it works:**
- If the time between image swaps is **less than** `rapidLimit`, it's considered a "rapid swap"
- During rapid swaps, transition animations are skipped and images swap instantly
- After rapid navigation stops, there's a 333ms cooldown before normal transitions resume
- This prevents stuttering when users rapidly click next/prev or hold down arrow keys
**Default:** `222` (222ms)
```typescript
vistaView({
elements: '#gallery a',
rapidLimit: 222, // default
});
```
---
# Basic Configuration
Get started with basic VistaView configuration
Path: /core/configuration/basic
Learn the fundamentals of configuring VistaView for your image galleries.
## Minimal Setup
The simplest way to use VistaView requires just two things: importing the library and specifying which elements to use.
### Using Anchor Tags (Recommended)
The recommended approach uses anchor tags wrapping images:
```html
```
```typescript
import { vistaView } from 'vistaview';
import 'vistaview/style.css';
vistaView({
elements: '#gallery a',
});
```
Benefits:
- Progressive loading from thumbnail to full-size
- Works without JavaScript
- SEO-friendly
### Using Images Directly
You can also select images directly:
```html
```
```typescript
vistaView({
elements: '#gallery img',
});
```
### Using Array of Images
You can also pass an array of image configuration objects directly:
```typescript
import type { VistaImgConfig } from 'vistaview';
const images: VistaImgConfig[] = [
{ src: '/images/photo1.jpg', alt: 'Photo 1' },
{ src: '/images/photo2.jpg', alt: 'Photo 2' },
{
src: '/images/photo3.jpg',
alt: 'Photo 3',
srcSet: '/images/photo3-800.jpg 800w, /images/photo3-1200.jpg 1200w',
},
];
vistaView({
elements: images,
});
```
**VistaImgConfig Type:**
```typescript
interface VistaImgConfig {
src: string; // Full-size image URL (required)
alt?: string; // Alt text for the image
srcSet?: string; // Responsive image srcset attribute
}
```
**Note:** Thumbnails are not supported when using an array. This approach is best for programmatically generated galleries.
## Return Value
The `vistaView` function returns an instance with methods to control the lightbox programmatically:
```typescript
const vista = vistaView({
elements: '#gallery a',
});
// Available methods:
vista.open(0); // Open lightbox at index 0
vista.close(); // Close the lightbox
vista.next(); // Navigate to next image
vista.prev(); // Navigate to previous image
vista.view(2); // Jump to image at index 2
vista.zoomIn(); // Zoom in
vista.zoomOut(); // Zoom out
vista.getCurrentIndex(); // Get current image index
vista.reset(); // Recalculate elements; for selectors: re-queries DOM and re-attaches click listeners; for arrays: updates element count only
vista.destroy(); // Clean up and remove lightbox
```
**VistaInterface Type:**
```typescript
interface VistaInterface {
open: (startIndex?: number) => void; // Open at specific index
close: () => Promise; // Close lightbox
reset: () => void; // For selectors: re-queries DOM & re-attaches click listeners; For arrays: updates count only
next: () => void; // Go to next image
prev: () => void; // Go to previous image
zoomIn: () => void; // Zoom in current image
zoomOut: () => void; // Zoom out current image
destroy: () => void; // Remove lightbox completely
getCurrentIndex: () => number; // Get current image index
view: (index: number) => void; // Navigate to specific index
}
```
## Multiple Gallery Configurations
When you need different lightbox configurations across different sections of your application, you have two main approaches:
### Approach 1: Multiple Instances (Recommended)
Create separate VistaView instances for each gallery with different configurations:
```typescript
// Product gallery with zoom enabled
const productGallery = vistaView({
elements: '#product-images a',
maxZoomLevel: 3,
arrowOnSmallScreens: true,
controls: {
topRight: ['zoomIn', 'zoomOut', 'close'],
},
});
// Portfolio gallery with minimal UI
const portfolioGallery = vistaView({
elements: '#portfolio a',
maxZoomLevel: 1, // No zoom
keyboardListeners: false,
controls: {
topRight: ['close'],
},
});
// Blog gallery with downloads
import { download } from 'vistaview/extensions/download';
const blogGallery = vistaView({
elements: '#blog-post img',
extensions: [download()],
});
```
**Advantages:**
- Each gallery is independent with its own configuration
- Different extensions per gallery
- No need to reconfigure or reset
- Straightforward and maintainable
**Memory:**
- Each instance maintains its own state and event listeners
- Automatically cleaned up when you call `destroy()`
### Approach 2: Single Instance with Dynamic Content
Use a single instance and update content dynamically. The approach differs based on whether you use selectors or arrays:
#### With String Selectors (DOM-based)
Update the DOM, then call `reset()` to re-query elements and re-attach listeners:
```typescript
const vista = vistaView({
elements: '#dynamic-gallery a',
maxZoomLevel: 2,
});
// Example Async function to fetch and update gallery
async function updateGallery(category: string) {
const response = await fetch(`/api/images?category=${category}`);
const images = await response.json();
const gallery = document.querySelector('#dynamic-gallery');
// Update DOM
gallery.innerHTML = images
.map(
(img: { src: string; alt: string }) => `
`
)
.join('');
// Re-query DOM and re-attach click listeners
vista.reset();
}
```
**How `reset()` works with selectors:**
- Re-queries the DOM using the original selector
- Updates `state.elmLength`
- Removes and re-attaches click event listeners
- Images become clickable automatically
#### With Arrays (Programmatic)
Mutate the array reference, then call `reset()` to update count:
```typescript
// Create array that will be mutated
const currentImages: VistaImgConfig[] = [];
const vista = vistaView({
elements: currentImages, // Stores the array reference
maxZoomLevel: 2,
});
// Example Async function to fetch and update gallery
async function updateGallery(category: string) {
const response = await fetch(`/api/images?category=${category}`);
const images = await response.json();
// Mutate the original array (don't reassign!)
currentImages.length = 0;
currentImages.push(...images);
// Update element count
vista.reset();
}
```
**How `reset()` works with arrays:**
- Reads `this.elements.length` to update count
- Does NOT attach click listeners (arrays have no DOM elements)
- You must call `open()` programmatically
**Advantages (both):**
- Single instance reduces memory
- Good for SPAs with dynamic content
- All content shares same configuration
**Limitations (both):**
- Cannot change configuration after initialization
- All galleries share same settings (zoom, extensions, controls)
### When to Destroy Instances
Always destroy instances when they're no longer needed:
```typescript
// Before page navigation in SPAs
function cleanup() {
productGallery.destroy();
portfolioGallery.destroy();
blogGallery.destroy();
}
// the following example in react and Vue
// is only needed if you are using
// hooks, composable, or creating and managing you own instance.
// In React - basic cleanup
useEffect(() => {
const vista = vistaView({ elements: '#gallery a' });
return () => vista.destroy();
}, []);
// In React - destroy and recreate when data changes
const [images, setImages] = useState([]);
useEffect(() => {
const vista = vistaView({
elements: images, // Works for both: arrays, or '#gallery a' when DOM re-renders
maxZoomLevel: 2,
});
return () => vista.destroy();
}, [images]);
// In Vue
onUnmounted(() => {
vista.destroy();
});
```
## Next Steps
- Explore [Animation Options](/core/configuration/animation) for timing control
- Discover [Controls](/core/configuration/controls) for UI customization
- See all available options in the [Complete Options](/core/configuration/complete)
---
# Options
Complete reference of all VistaView configuration options
Path: /core/configuration/complete
This page provides a comprehensive reference of all available configuration options for VistaView.
## Default Options
The value you see here are the default values.
```typescript
vistaView({
// Required: specify elements
elements: string | VistaImgConfig[],
// Animation & Timing
animationDurationBase: 333, // Base animation duration in ms
rapidLimit: 222, // Minimum time between rapid actions in ms
// Zoom & Navigation
maxZoomLevel: 2, // Maximum zoom multiplier (1 = 100%, 2 = 200%, etc.)
// Number of adjacent images to preload on each side
preloads: 1,
// UI Controls
keyboardListeners: true, // Enable keyboard navigation
arrowOnSmallScreens: false, // Show prev/next arrows on screens < 768px
initialZIndex: 1, // Starting z-index for the lightbox
// Control Placement
controls: {
topLeft: ['indexDisplay'], // Array of control names
topRight: ['zoomIn', 'zoomOut', 'close'],
topCenter: [],
bottomLeft: ['description'],
bottomRight: [],
bottomCenter: [],
},
// Extensions
extensions: [], // Array of extension objects
// Event Callbacks
onOpen: (vistaView) => {}, // Called when lightbox opens
onClose: (vistaView) => {}, // Called when lightbox closes
onImageView: (data, vistaView) => {}, // Called when viewing an image
onContentChange: (content, vistaView) => {}, // Called when image content changes
// Lifecycle: Custom Behavior Functions (override defaults)
initFunction: undefined, // Custom initialization (default: sets up swipe gestures)
openFunction: undefined, // Custom open behavior (default: positions image container)
imageSetupFunction: undefined, // Custom setup when navigating (default: none)
transitionFunction: undefined, // Custom transition animation (default: slide animation)
closeFunction: undefined, // Custom close behavior (default: none)
});
```
## Detailed Documentation
For detailed explanations and examples of each option, refer to the specific configuration sections:
- **[Basic Configuration](/core/configuration/basic)** - Getting started essentials
- **[Animation Options](/core/configuration/animation)** - Timing and transitions
- **[Zoom Options](/core/configuration/zoom)** - Zoom behavior
- **[Preloading](/core/configuration/preloading)** - Image preloading settings
- **[Control Configuration](/core/configuration/controls)** - UI controls placement
- **[Keyboard & UI Options](/core/configuration/keyboard)** - Keyboard and mobile settings
- **[Z-Index Configuration](/core/configuration/z-index)** - Z-index stacking
- **[Event Callbacks](/core/configuration/events)** - Lifecycle events
- **[Data Attributes](/core/configuration/data-attributes)** - HTML data attributes
- **[Lifecycle Functions](/core/configuration/lifecycle)** - Custom behavior overrides
---
# Data Attributes
Use HTML data attributes to customize VistaView behavior
Path: /core/configuration/data-attributes
VistaView uses data attributes to customize how images are displayed in the lightbox. These attributes provide fine-grained control over individual images without requiring JavaScript configuration.
## Available Attributes
| Attribute | Description | Priority |
| ----------------------- | ----------------------- | -------- |
| `data-vistaview-src` | Full-size image URL | Highest |
| `data-vistaview-srcset` | Responsive image srcset | Highest |
| `data-vistaview-alt` | Alt text for lightbox | Highest |
## Attribute Priority
VistaView follows a specific priority order when parsing elements:
### Image Source (`src`)
1. `data-vistaview-src` (highest priority)
2. `href` attribute (for `` tags)
3. `src` attribute (on the element itself)
4. `src` attribute (on child `` tag)
### Responsive Images (`srcset`)
1. `data-vistaview-srcset` (highest priority)
2. `srcset` attribute (on the element itself)
3. `srcset` attribute (on child `` tag)
### Alt Text (`alt`)
1. `data-vistaview-alt` (highest priority)
2. `alt` attribute (on the element itself)
3. `alt` attribute (on child `` tag)
## Examples
### Basic Override
Override the lightbox image URL while keeping the thumbnail:
```html
```
### Responsive Images
Provide different images based on the displayed image size. VistaView dynamically selects the most appropriate image as the image size changes:
```html
```
**How it works:**
- VistaView monitors the **image's display width** (not viewport width) and automatically switches to the optimal image from the srcset
- The image display width depends on the viewport and the image's aspect ratio (portrait images are constrained by height, landscape by width)
- Accounts for device pixel ratio (DPI) for high-resolution displays (e.g., Retina screens)
- Selects the smallest image that meets or exceeds the required display width
- Dynamically swaps images during opening animation and zoom gestures
**Format:** `"url {width}w, url {width}w, ..."` where width descriptors specify the image's actual pixel width.
:::note[Width descriptors only]
VistaView only supports the `w` (width) descriptor. Density descriptors like `1x` or `2x` are **not supported**. Use width descriptors with pixel values (e.g., `800w`, `1200w`) to enable responsive image selection.
:::
**Example with pixel calculations:**
```html
```
### Custom Alt Text
Display different text in the thumbnail vs lightbox:
```html
```
### Combining Attributes
Use multiple attributes together. When both `src` and `srcset` are provided, `srcset` takes precedence and `src` serves as fallback:
```html
```
**Priority order:** If `srcset` is available, VistaView uses responsive selection. The `src` attribute (or `data-vistaview-src`) is used only when `srcset` is not provided.
---
# Control Configuration
Configure UI controls placement and behavior
Path: /core/configuration/controls
## Built-in Controls
VistaView includes these built-in controls:
| Control | Description |
| -------------- | ----------------------------------------- |
| `indexDisplay` | Shows current image index (e.g., "1 / 5") |
| `zoomIn` | Zoom into the image |
| `zoomOut` | Zoom out of the image |
| `close` | Close the lightbox |
| `description` | Shows the image alt text |
## Control Placement
```typescript
vistaView({
elements: '#gallery a',
controls: {
topLeft: ['indexDisplay'],
topRight: ['zoomIn', 'zoomOut', 'close'],
bottomLeft: ['description'],
bottomRight: [],
bottomCenter: [],
},
});
```
## Adding Extension Controls
Extensions can add custom controls. See the [Extensions documentation](/extensions/overview) for available extensions.
```typescript
import { download } from 'vistaview/extensions/download';
vistaView({
elements: '#gallery a',
controls: {
topRight: ['zoomIn', 'zoomOut', 'download', 'close'], // Add 'download'
},
extensions: [download()], // Register extension
});
```
---
# Event Callbacks
Handle VistaView lifecycle events
Path: /core/configuration/events
## onOpen
Called when the lightbox opens:
```typescript
import type { VistaView } from 'vistaview';
vistaView({
elements: '#gallery a',
onOpen: (vistaView: VistaView) => {
console.log('Lightbox opened', vistaView);
},
});
```
## onClose
Called when the lightbox closes:
```typescript
import type { VistaView } from 'vistaview';
vistaView({
elements: '#gallery a',
onClose: (vistaView: VistaView) => {
console.log('Lightbox closed', vistaView);
},
});
```
## onImageView
Called when viewing an image (including on open):
```typescript
import type { VistaView, VistaData, VistaBox } from 'vistaview';
vistaView({
elements: '#gallery a',
onImageView: (data: VistaData, vistaView: VistaView) => {
console.log('Viewing image:', data.index.to);
console.log('Previous image:', data.index.from);
console.log('Navigation direction:', data.via);
// Access the current and previous images
if (data.images.to) {
console.log('Current images:', data.images.to);
}
// Access HTML elements
if (data.htmlElements.to) {
console.log('Current HTML elements:', data.htmlElements.to);
}
},
});
```
**Parameters:**
- `data: VistaData` - Navigation data
- `vistaView: VistaView` - The VistaView instance
**VistaData type:**
```typescript
type VistaData = {
htmlElements: {
from: HTMLElement[] | null; // Previous HTML elements
to: HTMLElement[] | null; // Current HTML elements
};
images: {
from: VistaBox[] | null; // Previous VistaBox instances
to: VistaBox[] | null; // Current VistaBox instances
};
index: {
from: number | null; // Previous image index (null on initial open)
to: number | null; // Current image index
};
via: {
next: boolean; // True if navigated via next
prev: boolean; // True if navigated via prev
};
};
```
## onContentChange
Called when the current image's content state changes (after zoom, pan, or when image finishes loading):
```typescript
import type { VistaView, VistaImageClone } from 'vistaview';
vistaView({
elements: '#gallery a',
onContentChange: (content: VistaImageClone, vistaView: VistaView) => {
console.log('Image state changed');
console.log('Current dimensions:', content.state.width, content.state.height);
console.log('Transform:', content.state.transform);
console.log('Zoom level:', content.state.transform.scale);
},
});
```
**Use cases:**
- Track zoom level changes
- Monitor image dimensions during resize
- Sync image state with external UI
- Analytics for user interactions
**Parameters:**
- `content: VistaImageClone` - Current image state (dimensions, transform, config)
- `vistaView: VistaView` - The VistaView instance
**VistaImageClone type:**
```typescript
type VistaImageClone = {
config: {
src: string; // Image source URL
alt?: string; // Alt text
srcSet?: string; // Responsive image srcset
};
origin: {
src: string; // Original source from HTML
srcSet: string; // Original srcset from HTML
borderRadius: string; // Original border radius
objectFit: string; // Original object-fit value
} | null;
parsedSrcSet?: {
src: string;
width: number;
}[];
element: string; // HTML string of the image element
thumb?: string; // HTML string of thumbnail (if exists)
index: number; // Image index in gallery
pos: number; // Position relative to current (-1, 0, 1)
state: {
width: number; // Current display width (px)
height: number; // Current display height (px)
transform: {
x: number; // Transform X offset (px)
y: number; // Transform Y offset (px)
scale: number; // Scale factor (1 = normal)
};
translate: {
x: number; // CSS translate X (px)
y: number; // CSS translate Y (px)
};
};
};
```
---
# Extensions
Add extended functionality to VistaView
Path: /core/configuration/extensions
## extensions
Array of extension functions that add functionality to VistaView. Extensions can add UI controls, handle different content types (videos, maps), or modify lightbox behavior.
See the [Extensions Overview](/extensions/overview) for complete documentation on all available extensions and their usage.
**Type:** `VistaExtension[]`
**Default:** `[]` (no extensions)
```typescript
import { vistaView } from 'vistaview';
import { download } from 'vistaview/extensions/download';
import { youtubeVideo } from 'vistaview/extensions/youtube-video';
vistaView({
elements: '#gallery a',
controls: {
// Add 'download' to controls for download extension
topRight: ['zoomIn', 'zoomOut', 'download', 'close'],
},
extensions: [download(), youtubeVideo()],
});
```
**Note:** Some extensions like `download` require adding their control name to the `controls` configuration.
## Available Extensions
VistaView provides optional extensions for:
- **UI Controls** - Download buttons, image story overlays
- **Video Platforms** - YouTube, Vimeo, Dailymotion, Wistia, Vidyard, Streamable
- **Maps** - Google Maps, Mapbox, OpenStreetMap
- **Development** - Logger for debugging
See the [Extensions Overview](/extensions/overview) for complete documentation on all available extensions and their usage.
---
# Configuration
Complete configuration reference for VistaView
Path: /core/configuration
---
# Keyboard & Touch Navigation
Configure keyboard shortcuts and touch gestures for desktop and mobile users
Path: /core/configuration/keyboard
## Keyboard Navigation
VistaView includes **built-in keyboard navigation** that's enabled by default.
### Keyboard Shortcuts
When the lightbox is open, the following keyboard shortcuts are available:
- **Arrow Left** (←) - Navigate to previous image
- **Arrow Right** (→) - Navigate to next image
- **Arrow Up** (↑) - Zoom in
- **Arrow Down** (↓) - Zoom out
- **Escape** (Esc) - Close lightbox
### Configuration
Control keyboard navigation via the `keyboardListeners` option:
```typescript
vistaView({
elements: '#gallery a',
keyboardListeners: true, // Default: enabled
});
```
To disable keyboard navigation:
```typescript
vistaView({
elements: '#gallery a',
keyboardListeners: false,
});
```
## Touch Gestures
VistaView automatically handles touch gestures with **no configuration needed**. All gestures work out-of-the-box on mobile devices.
### Pinch-to-Zoom
Use two fingers to zoom in and out:
- **Two-finger pinch out** - Zoom in
- **Two-finger pinch in** - Zoom out
The zoom is centered around the touch point (centroid of your fingers) for intuitive interaction. VistaView includes a cooldown period (111ms) after pinch gestures to prevent conflicts with other touch interactions.
### Swipe Navigation
Single-finger swipe gestures for navigation:
- **Horizontal swipe right** (>64px) - Navigate to previous image
- **Horizontal swipe left** (>64px) - Navigate to next image
- **Vertical swipe down** (>144px) - Close lightbox
**Note:** Swipe gestures only work when the image is not zoomed in. When zoomed, single-finger drag is used for panning.
### Pan/Drag
When an image is zoomed in:
- **Single finger drag** - Pan around the zoomed image
Pan is disabled at normal zoom level to allow swipe gestures for navigation and closing.
### Scroll-to-Zoom
On devices with a mouse or trackpad:
- **Scroll wheel** - Zoom in/out around cursor position
## Mobile-Specific Options
### arrowOnSmallScreens
Control whether navigation arrows are shown on mobile devices:
```typescript
vistaView({
elements: '#gallery a',
arrowOnSmallScreens: true, // Show arrows on screens < 768px (default: false)
});
```
By default, navigation arrows are hidden on screens smaller than 768px to provide a cleaner interface where users can swipe. Enable this option if you want to show arrow buttons on mobile devices.
## Advanced: Custom Touch Handling
For custom touch behaviors and gesture tracking, use the `registerPointerListener()` method:
```typescript
const vista = vistaView({ elements: '#gallery a' });
vista.registerPointerListener((e) => {
// Track pointer events
console.log('Event type:', e.event); // 'down' | 'move' | 'up' | 'cancel'
console.log('Active pointers:', e.pointers.length);
console.log('Pointer position:', e.pointer.x, e.pointer.y);
console.log('Zoom/pinch active:', e.hasInternalExecution);
// Access current state
console.log('Is zoomed:', e.state.zoomedIn);
console.log('Current index:', e.state.currentIndex);
});
```
### VistaExternalPointerListenerArgs Properties
- `event` - Event type: `'down'`, `'move'`, `'up'`, or `'cancel'`
- `pointer` - Current pointer data (x, y, movementX, movementY, id)
- `pointers` - Array of all active touch points/pointers
- `lastPointerLen` - Previous number of active pointers
- `state` - Current [VistaState](/api-reference/classes/vistastate) instance
- `hasInternalExecution` - `true` when VistaView is handling the gesture (zoom/pinch)
- `abortController` - Controller to abort ongoing animations
### Example: Custom Gesture Detection
```typescript
vista.registerPointerListener((e) => {
// Skip if VistaView is handling the event (zooming/pinching)
if (e.hasInternalExecution) return;
// Detect three-finger tap
if (e.event === 'down' && e.pointers.length === 3) {
console.log('Three-finger tap detected!');
// Custom action here
}
// Track swipe velocity
if (e.event === 'move' && e.pointers.length === 1) {
const velocity = Math.sqrt(e.pointer.movementX ** 2 + e.pointer.movementY ** 2);
console.log('Swipe velocity:', velocity);
}
});
```
## Customizing Swipe Behavior
The default swipe gesture behavior is implemented in VistaView's `initFunction` lifecycle hook. You can extend or replace this behavior:
```typescript
import { init as defaultInit } from 'vistaview/defaults/init';
vistaView({
elements: '#gallery a',
initFunction: (vistaView) => {
// Call default behavior (sets up swipe gestures)
defaultInit(vistaView);
// Add your custom initialization
vistaView.registerPointerListener((e) => {
// Your custom gesture handling
if (e.event === 'down' && e.pointers.length === 3) {
console.log('Three-finger tap!');
}
});
},
});
```
**Default initFunction behavior:**
- Registers a pointer listener for single-touch swipe gestures
- Vertical swipe down (>144px) closes the lightbox
- Horizontal swipe left/right (>64px) navigates between images
- Provides visual feedback during swipe (translates the image container)
To completely replace the default swipe behavior, provide your own `initFunction` without calling `defaultInit()`.
See [Lifecycle Functions](/core/configuration/lifecycle) for more details on customizing behavior.
## Related
- [VistaPointers API](/api-reference/classes/vistapointers) - Low-level pointer tracking
- [registerPointerListener()](/api-reference/classes/vistaview#registerpointerlistener) - Method documentation
- [VistaState](/api-reference/classes/vistastate) - State management
- [Lifecycle Functions](/core/configuration/lifecycle) - Custom behavior overrides
---
# Lifecycle Functions
Override default lifecycle behavior with custom functions
Path: /core/configuration/lifecycle
You can override default lifecycle functions to customize behavior at different stages:
```typescript
import {
vistaView,
// lifecycle functions
init,
open,
imageSetup,
transition,
close,
} from 'vistaview';
import type { VistaView, VistaData } from 'vistaview';
vistaView({
elements: '#gallery a',
// Custom initialization (runs once on instance creation)
initFunction: (vistaView: VistaView) => {
console.log('Custom init');
// default init, just here to show the actual init
init(vistaView);
},
// Custom open behavior (runs when lightbox opens)
openFunction: (vistaView: VistaView) => {
console.log('Custom open');
// default open, just here to show the actual open
open(vistaView);
},
// Custom setup when navigating between images
imageSetupFunction: (data: VistaData, vistaView: VistaView) => {
console.log('Setting up image:', data.index.to);
// default imageSetup, just here to show the actual imageSetup
imageSetup(data, vistaView);
},
// Custom transition animation
transitionFunction: async (
data: VistaData,
abortSignal: AbortSignal,
vistaView: VistaView
): Promise<{ cleanup: () => void; transitionEnded: Promise } | undefined> => {
console.log('Custom transition');
// default transition, just here to show the actual transition
return transition(data, abortSignal, vistaView);
},
// Custom close behavior (runs when lightbox closes)
closeFunction: (vistaView: VistaView) => {
console.log('Custom close');
// default close, just here to show the actual close
close(vistaView);
},
});
```
## VistaData Type
The `data` parameter passed to lifecycle functions contains information about the current and previous images:
```typescript
interface VistaData {
htmlElements: {
from: HTMLElement[] | null;
to: HTMLElement[] | null;
};
images: {
from: VistaBox[] | null;
to: VistaBox[] | null;
};
index: {
from: number | null;
to: number | null;
};
via: {
next: boolean;
prev: boolean;
};
}
```
See the [API Reference](/api-reference/main-function) for more details on these functions.
---
# Preloading
Configure image preloading for better navigation performance
Path: /core/configuration/preloading
## preloads
Number of adjacent images to preload:
```typescript
vistaView({
elements: '#gallery a',
preloads: 1, // default
});
```
**How it works:**
- Preloads adjacent images on both sides (previous and next)
- `preloads: 1` → loads 3 images total (current + 1 before + 1 after)
- `preloads: 2` → loads 5 images total (current + 2 before + 2 after)
- `preloads: 0` → only loads current image (saves bandwidth but causes loading delays)
**Trade-offs:**
- Higher values: Faster navigation, smoother experience, more bandwidth usage
- Lower values: Less bandwidth, but visible loading delays when navigating
---
# Z-Index Configuration
Configure z-index stacking for the lightbox
Path: /core/configuration/z-index
## initialZIndex
Set the z-index for the lightbox when opening or closing. When active, the lightbox automatically uses the maximum z-index (`2147483647`) to appear above all content.
**Default:** `1`
**Most users should leave this at the default value.**
```typescript
vistaView({
elements: '#gallery a',
initialZIndex: 1, // default
});
```
## Why leave it at 1?
VistaView renders its container at the bottom of the page (end of DOM). With the default `initialZIndex: 1`, it then brings the image to the center and raises the z-index to the maximum z-index. In effect, this requires z-index ordering:
- Your **sticky header** should use `z-index: 2` or higher to appear above the opening/closing lightbox
## Example with sticky header
```css
/* Your sticky header */
.site-header {
position: sticky;
z-index: 2; /* Appears above closed lightbox (z-index: 1) */
}
```
## How it works
- **Closed state:** Uses `initialZIndex` value (default: 1)
- **Active state:** Switches to `2147483647` (max z-index) in the middle of animation - always above everything
- **Closing state:** Transitions back to `initialZIndex` during animation
:::tip
Only change `initialZIndex` if you have z-index stacking context conflicts. For typical sticky headers, just set your header to `z-index: 2` or higher.
:::
---
# Zoom Options
Configure zoom behavior in VistaView
Path: /core/configuration/zoom
## maxZoomLevel
Defines the maximum zoom level as a multiplier of the image's natural dimensions.
**How it works:**
- VistaView maintains three zoom levels:
- **Minimum (0.5×)**: 50% of fitted size - zooming below this triggers close
- **Fitted**: Image fitted to viewport while maintaining aspect ratio
- **Maximum**: Natural image dimensions × `maxZoomLevel`
- Zoom automatically corrects if exceeded:
- Over maximum → animates back to max
- Under normal (but not closing) → animates back to fitted size
**Default:** `2` (200% of natural size)
```typescript
vistaView({
elements: '#gallery a',
maxZoomLevel: 2, // default - allows zoom to 200% of natural size
});
```
**Example:**
If an image is 1600×1200px and displays at 800×600px to fit the viewport:
- Minimum zoom: 400×300px (50% of fitted)
- Normal zoom: 800×600px (fitted to viewport)
- Maximum zoom: 3200×2400px (200% of natural 1600×1200px)
---
## Framework Integrations
---
# Getting Started with React
Learn how to integrate VistaView with React applications
Path: /integrations/react
VistaView provides official React bindings that offer both declarative components and hooks for React applications.
## Installation
import { Tabs, TabItem } from '@astrojs/starlight/components';
```bash
npm install vistaview
```
```bash
yarn add vistaview
```
```bash
pnpm add vistaview
```
```bash
bun add vistaview
```
## Component Approach (Recommended)
The `VistaView` component provides a declarative way to create image galleries:
```tsx
'use client'; // Required for Next.js and other React Server Components frameworks
import { VistaView } from 'vistaview/react';
import 'vistaview/style.css';
function Gallery() {
return (
);
}
```
### With Ref for Imperative Control
We expose the API and root container on the component ref as `{ vistaView, container }`.
💡 **Types:** You can import `VistaComponentRef` from `vistaview/react` (see the [Type Reference](#type-reference)):
```tsx
'use client'; // Required for Next.js and other React Server Components frameworks
import { useRef } from 'react';
import { VistaView } from 'vistaview/react';
import type { VistaComponentRef } from 'vistaview/react';
import 'vistaview/style.css';
function Gallery() {
const compRef = useRef(null);
return (
<>
>
);
}
```
### With Options
```tsx
'use client'; // Required for Next.js and other React Server Components frameworks
import { VistaView } from 'vistaview/react';
import type { VistaOpt, VistaView } from 'vistaview';
import 'vistaview/style.css';
// Define options outside component to prevent recreation on every render
const options: VistaOpt = {
maxZoomLevel: 3,
preloads: 2,
animationDurationBase: 400,
onOpen: (vistaView: VistaView): void => {
console.log('Gallery opened');
},
onClose: (vistaView: VistaView): void => {
console.log('Gallery closed');
},
};
function Gallery() {
return (
// selector defaults to '> a'
);
}
```
## With Extensions
```tsx
'use client'; // Required for Next.js and other React Server Components frameworks
import { VistaView } from 'vistaview/react';
import { download } from 'vistaview/extensions/download';
import 'vistaview/style.css';
// Define options outside component to prevent recreation on every render
const extensionOptions = {
controls: {
topRight: ['zoomIn', 'zoomOut', 'download', 'close'],
},
extensions: [download()],
};
function Gallery() {
return (
);
}
```
## Hook Approach
Use the `useVistaView` hook for more control over the gallery instance:
```tsx
'use client'; // Required for Next.js and other React Server Components frameworks
import { useVistaView } from 'vistaview/react';
import { download } from 'vistaview/extensions/download';
import 'vistaview/style.css';
function Gallery() {
const vista = useVistaView({
elements: '#gallery > a',
controls: {
topRight: ['zoomIn', 'zoomOut', 'download', 'close'],
},
extensions: [download()],
});
return (
);
}
```
### Type Reference
**`VistaViewProps`**
```ts
interface VistaViewProps {
children: ReactNode;
selector?: string; // defaults to "> a"
options?: VistaOpt; // passes through to core options
ref?: React.Ref;
}
```
- **children**: The gallery markup (usually `` items).
- **selector**: CSS selector used to locate items inside the container.
- **options**: Configuration passed to the core `VistaView` instance (`VistaOpt`).
- **ref**: React ref that receives a `VistaComponentRef` for imperative control.
**`VistaComponentRef`**
```ts
type VistaComponentRef = {
vistaView: VistaInterface | null;
container: HTMLDivElement | null
} | null;
```
- **vistaView**: The runtime API instance (`VistaInterface`) — use it to call `.open()`, `.next()`, `.prev()`, `.zoomIn()`, `.zoomOut()`, `.close()`, `.destroy()`, etc.
- **container**: The root DOM element that wraps the gallery — useful for queries or DOM measurements.
**Related types**
- `VistaOpt` — core configuration object (see `/core/configuration/complete` or `main/src/lib/types.ts` for full shape).
- `VistaInterface` — runtime API methods available on `vistaView`.
**Import example**
```ts
import type { VistaComponentRef, VistaViewProps } from 'vistaview/react';
```
## Next Steps
- Explore [configuration options](/core/configuration/complete)
- Learn about [extensions](/extensions/overview)
- Customize the [styling](/styling/themes)
---
# Getting Started with Solid
Learn how to integrate VistaView with Solid applications
Path: /integrations/solid
VistaView provides a `useVistaView` hook for SolidJS applications.
## Installation
import { Tabs, TabItem } from '@astrojs/starlight/components';
```bash
npm install vistaview
```
```bash
yarn add vistaview
```
```bash
pnpm add vistaview
```
```bash
bun add vistaview
```
## Component Approach (Recommended)
The `VistaView` component is the recommended way to use VistaView in Solid applications:
```tsx
import { VistaView } from 'vistaview/solid';
import 'vistaview/style.css';
function Gallery() {
return (
);
}
```
## Hook Approach
Use the `useVistaView` hook when you need more control:
```tsx
import { useVistaView } from 'vistaview/solid';
import 'vistaview/style.css';
function Gallery() {
const galleryId = 'vistaview-demo';
const vista = useVistaView({
elements: `#${galleryId} > a`,
});
return (
<>
>
);
}
```
## Imperative Control with Component
Access the API through the `componentRef` callback prop:
```tsx
import { VistaView } from 'vistaview/solid';
import type { VistaInterface } from 'vistaview';
import 'vistaview/style.css';
function Gallery() {
let vista: VistaInterface | null = null;
let container: HTMLDivElement | undefined;
return (
<>
{
vista = api?.vistaView ?? null;
container = api?.container;
}}
>
>
);
}
```
## With Options
```tsx
import { useVistaView } from 'vistaview/solid';
import type { VistaOpt } from 'vistaview';
import 'vistaview/style.css';
// Define options outside component to prevent recreation on every render
const options: VistaOpt = {
maxZoomLevel: 3,
preloads: 2,
animationDurationBase: 400,
onOpen: (vistaView) => console.log('Gallery opened'),
onClose: (vistaView) => console.log('Gallery closed'),
};
function Gallery() {
const id = 'gallery-' + Math.random().toString(36).slice(2);
const vista = useVistaView({
elements: `#${id} > a`,
...options,
});
return (
);
}
```
## With Extensions
```tsx
import { useVistaView } from 'vistaview/solid';
import { download } from 'vistaview/extensions/download';
import 'vistaview/style.css';
function Gallery() {
const id = 'gallery-' + Math.random().toString(36).slice(2);
const vista = useVistaView({
elements: `#${id} > a`,
controls: {
topRight: ['zoomIn', 'zoomOut', 'download', 'close'],
},
extensions: [download()],
});
return (
);
}
```
## Reactive Updates
VistaView works with Solid's reactive system:
```tsx
import { createSignal } from 'solid-js';
import { useVistaView } from 'vistaview/solid';
import 'vistaview/style.css';
function Gallery() {
const [images, setImages] = createSignal([
{ src: '/images/photo1.jpg', alt: 'Photo 1' },
{ src: '/images/photo2.jpg', alt: 'Photo 2' },
]);
const id = 'gallery-' + Math.random().toString(36).slice(2);
const vista = useVistaView({
elements: `#${id} > a`,
});
return (
{images().map((img) => (
))}
);
}
```
## SolidStart
VistaView works with SolidStart. Make sure to use client-side rendering:
```tsx
import { lazy } from 'solid-js';
const Gallery = lazy(() => import('./Gallery'));
function Page() {
return (
);
}
```
## Next Steps
- Explore [configuration options](/core/configuration/complete)
- Learn about [extensions](/extensions/overview)
- Customize the [styling](/styling/themes)
---
# Getting Started with Svelte
Learn how to integrate VistaView with Svelte applications
Path: /integrations/svelte
VistaView provides a `VistaView` Svelte component (recommended) and a lower-level `useVistaView` hook for advanced use cases.
## Installation
import { Tabs, TabItem } from '@astrojs/starlight/components';
```bash
npm install vistaview
```
```bash
yarn add vistaview
```
```bash
pnpm add vistaview
```
```bash
bun add vistaview
```
## Component-first usage (recommended)
The recommended, primary way to use VistaView in Svelte is the `VistaView` component. It handles lifecycle, DOM changes, and provides a simple imperative API via `bind:this` and `getApi()`.
### Basic example
```svelte
```
### Imperative Control
If you need programmatic access to the gallery API, use the `vistaRef` callback prop:
```svelte
{
vista = api?.vistaView ?? null;
container = api?.container ?? null;
}}>
```
### Options
```svelte
```
### Extensions
```svelte
```
> **Tip:** prefer the component when your gallery content is dynamic, as it observes DOM changes and re-initializes automatically.
## Hook approach (advanced)
The `useVistaView` hook is a lower-level API. Use it for non-component contexts or when you need manual control. The hook handles lifecycle internally (`onMount`/`onDestroy`), so you can call it at the top level.
```svelte
```
## Low-level usage
You can call the core `vistaView` function directly when embedding in non-component contexts:
```svelte
```
## SvelteKit
Use the `VistaView` component in SvelteKit apps; it handles lifecycle and DOM updates automatically. If you need the hook, initialize it inside `onMount` to avoid SSR issues.
## Types
```ts
import type { VistaViewProps, VistaComponentRef } from 'vistaview/svelte';
```
## Best practices & troubleshooting
- Prefer the component for most cases (dynamic content, SvelteKit, simpler lifecycle).
- Keep `options` objects stable (define outside render scope) to avoid unnecessary re-initializations.
- Use optional chaining (e.g., `comp?.getApi()?.vistaView?.open(0)`) when calling methods that may not be ready yet.
- If using the hook and the DOM changes dynamically, re-initialize or prefer the component.
## Next Steps
- Explore [configuration options](/core/configuration/complete)
- Learn about [extensions](/extensions/overview)
- Customize the [styling](/styling/themes)
---
# Getting Started with Vanilla JavaScript
Learn how to use VistaView with vanilla JavaScript
Path: /integrations/vanilla
VistaView works perfectly with vanilla JavaScript - no framework needed!
## Installation
import { Tabs, TabItem } from '@astrojs/starlight/components';
```bash
npm install vistaview
```
```bash
yarn add vistaview
```
```bash
pnpm add vistaview
```
```bash
bun add vistaview
```
```javascript
import { vistaView } from 'vistaview';
import 'vistaview/style.css';
const gallery = vistaView({
elements: '#gallery a',
});
```
### Using CDN (UMD)
For quick prototyping or non-bundler environments:
```html
```
## Using Data Attributes
You can use `data-vistaview-src` to specify high-resolution images:
```html
```
## With Extensions (ESM)
```html
```
## With Extensions (UMD)
```html
```
## Using with Images Array
Instead of DOM elements, you can pass an array of image objects:
```javascript
vistaView({
elements: [
{ src: '/images/photo1.jpg', alt: 'Photo 1' },
{
src: '/images/photo2-800.jpg',
alt: 'Photo 2',
srcSet: '/images/photo2-800.jpg 800w, /images/photo2-1200.jpg 1200w',
},
],
});
```
**Note:** When using an array, thumbnails are not supported. Use DOM elements if you need progressive loading.
## Available Methods
```javascript
const gallery = vistaView({ elements: '#gallery a' });
// Open lightbox at specific index (0-based)
gallery.open(0);
// Close lightbox
gallery.close();
// Navigate to next image
gallery.next();
// Navigate to previous image
gallery.prev();
// Go to specific image
gallery.view(2);
// Get current image index
const currentIndex = gallery.getCurrentIndex();
// Destroy instance and cleanup
gallery.destroy();
```
## Event Callbacks
```javascript
vistaView({
elements: '#gallery a',
onOpen: (vistaView) => {
console.log('Gallery opened');
},
onClose: (vistaView) => {
console.log('Gallery closed');
},
onImageView: (data) => {
console.log('Viewing image:', data.index.to);
},
});
```
## Next Steps
- Explore [configuration options](/core/configuration/complete)
- Learn about [extensions](/extensions/overview)
- Customize the [styling](/styling/themes)
---
# Getting Started with Vue
Learn how to integrate VistaView with Vue 3 applications
Path: /integrations/vue
VistaView provides official Vue 3 bindings with both a declarative component and a composable.
## Installation
import { Tabs, TabItem } from '@astrojs/starlight/components';
```bash
npm install vistaview
```
```bash
yarn add vistaview
```
```bash
pnpm add vistaview
```
```bash
bun add vistaview
```
## Component Approach (Recommended)
The `VistaView` component provides a declarative way to create image galleries. Any additional HTML attributes (e.g., `class`, `style`, `data-*`, `aria-*`) passed to the component are forwarded to the root `
```
## With Extensions
Extensions can be used with both the component and composable approaches.
### Component with Extensions
```vue
```
### Composable with Extensions
```vue
```
## Options API
If you prefer the Options API:
```vue
```
## Next Steps
- Explore [configuration options](/core/configuration/complete)
- Learn about [extensions](/extensions/overview)
- Customize the [styling](/styling/themes)
---
## Extensions
---
# Extensions Overview
Extend VistaView with powerful extensions
Path: /extensions/overview
VistaView provides optional extensions for additional functionality. Extensions are available in both ESM and UMD formats and can add UI controls, handle different content types, or modify behavior.
## Extension Types
### UI Extensions
Add interactive controls to the lightbox:
- **[Download](/extensions/download)** - Download button for saving high-resolution images
- **[Image Story](/extensions/image-story)** - Display rich HTML content alongside images
### Video Platform Extensions
Embed videos from popular platforms:
- **[YouTube](/extensions/youtube-video)** - Embed YouTube videos
- **[Vimeo](/extensions/vimeo-video)** - Embed Vimeo videos
- **[Dailymotion](/extensions/dailymotion-video)** - Embed Dailymotion videos
- **[Wistia](/extensions/wistia-video)** - Embed Wistia videos
- **[Vidyard](/extensions/vidyard-video)** - Embed Vidyard videos
- **[Streamable](/extensions/streamable-video)** - Embed Streamable videos
### Map Extensions
Embed interactive maps:
- **[Google Maps](/extensions/google-maps)** - Embed Google Maps (requires API key)
- **[Mapbox](/extensions/mapbox)** - Embed Mapbox GL JS maps (requires access token)
- **[OpenStreetMap](/extensions/openstreetmap)** - Embed OpenStreetMap with Leaflet.js (free)
### Development Extensions
- **[Logger](/extensions/logger)** - Debug extension that logs all lifecycle events
## Using Extensions
### ESM (Module Bundlers)
```javascript
import { vistaView } from 'vistaview';
import { download } from 'vistaview/extensions/download';
import { youtubeVideo } from 'vistaview/extensions/youtube-video';
vistaView({
elements: '#gallery > a',
controls: {
topRight: ['zoomIn', 'zoomOut', 'download', 'close'],
},
extensions: [download(), youtubeVideo()],
});
```
### UMD (CDN)
```html
```
## Extension Sizes
All extensions are optimized for minimal bundle size:
| Extension | ESM Size | UMD Size |
| ----------------- | ------------------------ | ----------------------- |
| logger | 0.60 KB (0.26 KB gzip) | 0.72 KB (0.36 KB gzip) |
| download | 1.58 KB (0.78 KB gzip) | 1.50 KB (0.81 KB gzip) |
| streamable-video | 2.53 KB (1.13 KB gzip) | 2.22 KB (1.12 KB gzip) |
| vimeo-video | 2.44 KB (1.12 KB gzip) | 2.18 KB (1.11 KB gzip) |
| vidyard-video | 2.53 KB (1.13 KB gzip) | 2.24 KB (1.11 KB gzip) |
| dailymotion-video | 2.63 KB (1.15 KB gzip) | 2.30 KB (1.14 KB gzip) |
| wistia-video | 2.73 KB (1.24 KB gzip) | 2.45 KB (1.24 KB gzip) |
| youtube-video | 2.89 KB (1.30 KB gzip) | 2.56 KB (1.28 KB gzip) |
| google-maps | 3.53 KB (1.54 KB gzip) | 3.07 KB (1.49 KB gzip) |
| openstreetmap | 4.75 KB (1.88 KB gzip) | 4.10 KB (1.77 KB gzip) |
| mapbox | 4.91 KB (1.90 KB gzip) | 4.32 KB (1.80 KB gzip) |
| image-story | 29.56 KB (10.06 KB gzip) | 23.36 KB (9.27 KB gzip) |
## Creating Custom Extensions
Want to create your own extension? Check out the [Extensions Authoring Guide](/extensions/authoring).
## Extension Capabilities
Extensions can:
- **Add UI controls** - Buttons, panels, overlays
- **Handle custom content** - Videos, maps, 3D models, etc.
- **Modify behavior** - Custom transitions, interactions
- **Track events** - Analytics, logging, debugging
- **Enhance functionality** - Download, share, annotations
## Next Steps
- Browse individual [extension documentation](/extensions/download)
- Learn to [create your own extensions](/extensions/authoring)
- See the [API Reference](/api-reference/main-function)
---
# Streamable Video Extension
Embed Streamable videos in the lightbox
Path: /extensions/streamable-video
The Streamable Video extension allows you to embed Streamable videos in the VistaView lightbox instead of images.
## Installation
### ESM (Module Bundlers)
```javascript
import { vistaView } from 'vistaview';
import { streamableVideo } from 'vistaview/extensions/streamable-video';
import 'vistaview/style.css';
vistaView({
elements: '#gallery > a',
extensions: [streamableVideo()],
});
```
### UMD (CDN)
```html
```
## Usage
Create links pointing to Streamable video URLs:
```html
```
## Supported URL Formats
The extension automatically detects and parses these Streamable URL formats:
- `https://streamable.com/VIDEO_ID`
- `https://streamable.com/e/VIDEO_ID`
## Features
- **Autoplay** - Videos automatically start playing when opened
- **Responsive sizing** - Videos maintain 16:9 aspect ratio
- **Full controls** - All Streamable player controls available
## Video Size
The extension creates videos with a maximum width of 800px (or window width, whichever is smaller) while maintaining a 16:9 aspect ratio.
## Bundle Size
- **ESM:** 2.69 KB (1.24 KB gzip)
- **UMD:** 13.73 KB (4.19 KB gzip)
## Limitations
- **No zoom controls** - Videos cannot be zoomed like images
- **Requires internet connection** - Videos stream from Streamable
- **Public videos only** - Extension works with publicly accessible videos
## Next Steps
- Try other video extensions: [YouTube](/extensions/youtube-video), [Vimeo](/extensions/vimeo-video)
- Learn about [creating custom extensions](/extensions/authoring)
- Explore other [extensions](/extensions/overview)
---
# Vidyard Video Extension
Embed Vidyard videos in the lightbox
Path: /extensions/vidyard-video
The Vidyard Video extension allows you to embed Vidyard videos in the VistaView lightbox instead of images.
## Installation
### ESM (Module Bundlers)
```javascript
import { vistaView } from 'vistaview';
import { vidyardVideo } from 'vistaview/extensions/vidyard-video';
import 'vistaview/style.css';
vistaView({
elements: '#gallery > a',
extensions: [vidyardVideo()],
});
```
### UMD (CDN)
```html
```
## Usage
Create links pointing to Vidyard video URLs:
```html
```
## Supported URL Formats
The extension automatically detects and parses Vidyard video URLs containing video IDs.
## Features
- **Autoplay** - Videos automatically start playing when opened
- **Responsive sizing** - Videos maintain 16:9 aspect ratio
- **Full controls** - All Vidyard player controls available
- **High quality** - Videos play at the best available quality
## Video Size
The extension creates videos with a maximum width of 800px (or window width, whichever is smaller) while maintaining a 16:9 aspect ratio.
## Bundle Size
- **ESM:** 2.73 KB (1.24 KB gzip)
- **UMD:** 13.75 KB (4.19 KB gzip)
## Limitations
- **No zoom controls** - Videos cannot be zoomed like images
- **Requires internet connection** - Videos stream from Vidyard
- **Vidyard account required** - Videos must be hosted on Vidyard
## Next Steps
- Try other video extensions: [YouTube](/extensions/youtube-video), [Vimeo](/extensions/vimeo-video)
- Learn about [creating custom extensions](/extensions/authoring)
- Explore other [extensions](/extensions/overview)
---
# Download Extension
Add a download button to save images
Path: /extensions/download
The Download extension adds a button that allows users to download the currently viewed high-resolution image.
## Installation
### ESM (Module Bundlers)
```javascript
import { vistaView } from 'vistaview';
import { download } from 'vistaview/extensions/download';
import 'vistaview/style.css';
vistaView({
elements: '#gallery > a',
controls: {
topRight: ['zoomIn', 'zoomOut', 'download', 'close'],
},
extensions: [download()],
});
```
### UMD (CDN)
```html
```
## Features
- **Download button** - Adds a download control to the lightbox
- **Automatic filename** - Uses the image's alt text as the download filename
- **Loading state** - Shows a pulsing animation while downloading
- **Cross-origin support** - Handles CORS-protected images via fetch
## Usage
The download button appears in the control area you specify. When clicked, it:
1. Fetches the high-resolution image
2. Creates a blob URL
3. Triggers a download with the image's alt text as the filename
4. Cleans up the temporary blob URL
## Customization
### Control Position
```javascript
vistaView({
elements: '#gallery > a',
controls: {
topRight: ['download', 'close'], // Position at top right
// Or:
topLeft: ['download'], // Position at top left
bottomRight: ['download'], // Position at bottom right
},
extensions: [download()],
});
```
### Styling
The download button uses the standard VistaView control styling and can be customized with CSS:
```css
.vvw-ctrl-download {
--vvw-ui-bg-color: rgba(0, 150, 255, 0.3);
}
.vvw-ctrl-download:hover {
--vvw-ui-bg-color: rgba(0, 150, 255, 0.5);
}
/* Pulsing animation during download */
.vvw-ctrl-download.vvw--pulsing {
animation: pulse 1s infinite;
}
@keyframes pulse {
0%,
100% {
opacity: 1;
}
50% {
opacity: 0.5;
}
}
```
## Bundle Size
- **ESM:** 1.42 KB (0.70 KB gzip)
- **UMD:** 1.41 KB (0.79 KB gzip)
## Browser Compatibility
Works in all modern browsers that support:
- Fetch API
- Blob URLs
- Download attribute on anchor elements
For older browsers, consider using a polyfill or the extension will gracefully fail.
## Example
```javascript
import { vistaView } from 'vistaview';
import { download } from 'vistaview/extensions/download';
import 'vistaview/style.css';
vistaView({
elements: '#gallery > a',
controls: {
topRight: ['zoomIn', 'zoomOut', 'download', 'close'],
},
extensions: [download()],
});
```
```html
```
When users click the download button, the image will be saved with the filename based on the alt text (e.g., "Beautiful Sunset.jpg").
## Next Steps
- Explore other [extensions](/extensions/overview)
- Learn about [creating custom extensions](/extensions/authoring)
- See the [configuration options](/core/configuration/complete)
---
# Dailymotion Video Extension
Embed Dailymotion videos in the lightbox
Path: /extensions/dailymotion-video
The Dailymotion Video extension allows you to embed Dailymotion videos in the VistaView lightbox instead of images.
## Installation
### ESM (Module Bundlers)
```javascript
import { vistaView } from 'vistaview';
import { dailymotionVideo } from 'vistaview/extensions/dailymotion-video';
import 'vistaview/style.css';
vistaView({
elements: '#gallery > a',
extensions: [dailymotionVideo()],
});
```
### UMD (CDN)
```html
```
## Usage
Create links pointing to Dailymotion video URLs:
```html
```
## Automatic Thumbnail Generation
The extension provides helper functions to generate Dailymotion thumbnail URLs from video URLs:
```javascript
import {
getDailymotionThumbnail,
parseDailymotionVideoId,
} from 'vistaview/extensions/dailymotion-video';
// Generate thumbnail URL from video URL
const thumbnailUrl = getDailymotionThumbnail('https://www.dailymotion.com/video/x8abcde');
// Returns: "https://www.dailymotion.com/thumbnail/video/x8abcde"
// Or extract just the video ID
const videoId = parseDailymotionVideoId('https://dai.ly/x8abcde');
// Returns: "x8abcde"
```
## Complete Example
```html
```
## Supported URL Formats
The extension automatically detects and parses these Dailymotion URL formats:
- `https://www.dailymotion.com/video/VIDEO_ID`
- `https://dailymotion.com/video/VIDEO_ID`
- `https://dai.ly/VIDEO_ID`
## Features
- **Autoplay** - Videos automatically start playing when opened
- **Responsive sizing** - Videos maintain 16:9 aspect ratio
- **Full controls** - All Dailymotion player controls available
- **High quality** - Videos play at the best available quality
## Mixing Images and Videos
You can mix images and Dailymotion videos in the same gallery:
```html
```
## Video Size
The extension creates videos with a maximum width of 800px (or window width, whichever is smaller) while maintaining a 16:9 aspect ratio.
## Bundle Size
- **ESM:** 2.80 KB (1.26 KB gzip)
- **UMD:** 13.82 KB (4.21 KB gzip)
## Limitations
- **No zoom controls** - Videos cannot be zoomed like images
- **Requires internet connection** - Videos stream from Dailymotion
- **Dailymotion Terms of Service** - Ensure compliance with Dailymotion's ToS
- **Regional restrictions** - Some videos may be region-restricted
## Example with Multiple Video Platforms
```javascript
import { vistaView } from 'vistaview';
import { youtubeVideo } from 'vistaview/extensions/youtube-video';
import { vimeoVideo } from 'vistaview/extensions/vimeo-video';
import { dailymotionVideo } from 'vistaview/extensions/dailymotion-video';
vistaView({
elements: '#gallery > a',
extensions: [youtubeVideo(), vimeoVideo(), dailymotionVideo()],
});
```
## Next Steps
- Try other video extensions: [YouTube](/extensions/youtube-video), [Vimeo](/extensions/vimeo-video)
- Learn about [creating custom extensions](/extensions/authoring)
- Explore other [extensions](/extensions/overview)
---
# Mapbox Extension
Embed Mapbox GL JS maps in the lightbox
Path: /extensions/mapbox
The Mapbox extension allows you to embed interactive Mapbox GL JS maps in the VistaView lightbox instead of images.
## Installation
### ESM (Module Bundlers)
```javascript
import { vistaView } from 'vistaview';
import { mapbox } from 'vistaview/extensions/mapbox';
import 'vistaview/style.css';
vistaView({
elements: '#gallery > a',
extensions: [mapbox({ accessToken: 'YOUR_MAPBOX_ACCESS_TOKEN' })],
});
```
### UMD (CDN)
```html
```
## Requirements
You need a Mapbox access token to use this extension. Get one from [Mapbox](https://account.mapbox.com/).
## Configuration
### accessToken (required)
Your Mapbox access token:
```javascript
mapbox({
accessToken: 'pk.your_mapbox_token_here',
});
```
## Usage
Create links with Mapbox-compatible coordinate URLs:
```html
```
## URL Format
Use this format in your `href` attribute:
```
mapbox://LATITUDE,LONGITUDE,ZOOM
```
Example:
```
mapbox://40.7580,-73.9855,15
```
Parameters:
- **LATITUDE**: Latitude coordinate (e.g., 40.7580)
- **LONGITUDE**: Longitude coordinate (e.g., -73.9855)
- **ZOOM**: Zoom level (1-22, where 1 is world view and 22 is street level)
## Features
- **Interactive maps** - Full Mapbox GL JS functionality
- **Responsive sizing** - Maps adapt to lightbox size
- **Multiple styles** - Streets, satellite, outdoors, etc.
- **Smooth animations** - Hardware-accelerated rendering
- **Vector tiles** - Sharp rendering at any zoom level
## Map Size
The extension creates maps with a maximum width of 800px (or window width, whichever is smaller) while maintaining a 16:9 aspect ratio.
## Map Styles
By default, the extension uses Mapbox's standard style. You can customize this by modifying the extension code or creating a custom version.
## Mixing Images and Maps
You can mix images and Mapbox maps in the same gallery:
```html
```
## Bundle Size
- **ESM:** 4.99 KB (1.93 KB gzip)
- **UMD:** 15.63 KB (4.81 KB gzip)
Note: Mapbox GL JS library (~500KB) is loaded from CDN when a map is displayed.
## Free Tier
Mapbox offers a generous free tier:
- 50,000 map loads per month
- No credit card required to start
Check [Mapbox pricing](https://www.mapbox.com/pricing) for current limits.
## Limitations
- **Requires access token** - Must have valid Mapbox token
- **Usage limits** - Subject to Mapbox API quotas
- **Internet connection required** - Maps load from Mapbox servers
- **Large library** - Mapbox GL JS is loaded from CDN (~500KB)
## Security
**Best practices:**
1. Use public tokens (start with `pk.`) for client-side use
2. Restrict tokens to specific URLs in production
3. Monitor usage in Mapbox dashboard
4. Rotate tokens periodically
## Next Steps
- Try other map extensions: [Google Maps](/extensions/google-maps), [OpenStreetMap](/extensions/openstreetmap)
- Learn about [creating custom extensions](/extensions/authoring)
- Explore other [extensions](/extensions/overview)
---
# OpenStreetMap Extension
Embed OpenStreetMap with Leaflet.js in the lightbox (Free)
Path: /extensions/openstreetmap
The OpenStreetMap extension allows you to embed interactive OpenStreetMap maps using Leaflet.js in the VistaView lightbox. **No API key required** - completely free!
## Installation
### ESM (Module Bundlers)
```javascript
import { vistaView } from 'vistaview';
import { openStreetMap } from 'vistaview/extensions/openstreetmap';
import 'vistaview/style.css';
vistaView({
elements: '#gallery > a',
extensions: [openStreetMap()],
});
```
### UMD (CDN)
```html
```
## Usage
Create links with OpenStreetMap-compatible coordinate URLs:
```html
```
## URL Format
Use this format in your `href` attribute:
```
osm://LATITUDE,LONGITUDE,ZOOM
```
Example:
```
osm://40.7580,-73.9855,15
```
Parameters:
- **LATITUDE**: Latitude coordinate (e.g., 40.7580)
- **LONGITUDE**: Longitude coordinate (e.g., -73.9855)
- **ZOOM**: Zoom level (1-19, where 1 is world view and 19 is street level)
## Features
- **100% Free** - No API keys, no billing, no usage limits
- **Interactive maps** - Full Leaflet.js functionality
- **Responsive sizing** - Maps adapt to lightbox size
- **Zoom controls** - Standard map controls
- **Attribution** - Properly credits OpenStreetMap contributors
## Map Size
The extension creates maps with a maximum width of 800px (or window width, whichever is smaller) while maintaining a 16:9 aspect ratio.
## Mixing Images and Maps
You can mix images and OpenStreetMap maps in the same gallery:
```html
```
## Bundle Size
- **ESM:** 4.79 KB (1.90 KB gzip)
- **UMD:** 15.43 KB (4.79 KB gzip)
Note: Leaflet.js library (~150KB) is loaded from CDN when a map is displayed.
## Why Choose OpenStreetMap?
### Advantages
- ✅ **Completely free** - No API keys or billing
- ✅ **No usage limits** - Unlimited map loads
- ✅ **Open source** - Community-driven project
- ✅ **Privacy-friendly** - No tracking by default
- ✅ **Lightweight** - Smaller than commercial alternatives
### Considerations
- Map styles are more basic than commercial providers
- Fewer built-in features compared to Google Maps/Mapbox
- Relies on community tile servers
## Tile Servers
By default, the extension uses OpenStreetMap's tile servers. Please be respectful:
- Don't make excessive requests
- Cache tiles when possible
- Consider using your own tile server for high-traffic sites
For production sites with high traffic, consider:
- [Mapbox](https://www.mapbox.com/) (has free tier)
- Self-hosted tile server
- Commercial OpenStreetMap providers
## Customization
The extension uses standard OpenStreetMap tiles. To use custom tile servers or styles, you'll need to create a custom version based on the extension source code.
## Attribution
The extension automatically includes proper attribution to OpenStreetMap contributors as required by the OpenStreetMap license.
## Limitations
- **Internet connection required** - Maps load from tile servers
- **Basic styling** - Standard OpenStreetMap appearance only
- **Tile server load** - Respect the free tile server's resources
## Example with Multiple Maps
```html
```
## Next Steps
- Try other map extensions: [Google Maps](/extensions/google-maps), [Mapbox](/extensions/mapbox)
- Learn about [creating custom extensions](/extensions/authoring)
- Explore other [extensions](/extensions/overview)
---
# Image Story Extension
Display rich HTML content alongside images
Path: /extensions/image-story
The Image Story extension allows you to display rich HTML content (stories, descriptions, captions) below images in the lightbox. Content is loaded on-demand and cached for performance.
## Installation
### ESM (Module Bundlers)
```javascript
import { vistaView } from 'vistaview';
import { imageStory } from 'vistaview/extensions/image-story';
import 'vistaview/style.css';
import 'vistaview/styles/extensions/image-story.css';
vistaView({
elements: '#gallery > a',
extensions: [
imageStory({
getStory: async (index) => {
const response = await fetch(`/api/stories/${index}`);
const data = await response.json();
return { content: data.html };
},
}),
],
});
```
### UMD (CDN)
```html
```
## Configuration
### getStory (required)
A function that returns a promise resolving to a story object:
```typescript
getStory: (imageIndex: number) => Promise;
```
**StoryResult interface:**
```typescript
interface StoryResult {
content: string; // HTML content (will be sanitized)
onLoad?: () => void; // Called when story is displayed
onUnload?: () => void; // Called when navigating away
}
```
### maxStoryCache (optional)
Maximum number of stories to keep in memory. Default: `5`
```javascript
imageStory({
getStory: async (index) => {
/* ... */
},
maxStoryCache: 10, // Keep 10 stories cached
});
```
## Features
- **Rich HTML content** - Display formatted text, images, links, etc.
- **On-demand loading** - Stories are fetched only when needed
- **Smart caching** - Recently viewed stories are cached
- **Auto-sanitization** - HTML is automatically sanitized using DOMPurify
- **Expandable panel** - Users can expand/collapse the story
- **Lifecycle hooks** - onLoad/onUnload for custom behavior
## Usage Examples
### Basic Usage
```javascript
import { imageStory } from 'vistaview/extensions/image-story';
vistaView({
elements: '#gallery > a',
extensions: [
imageStory({
getStory: async (index) => ({
content: `
',
};
}
},
});
```
### With Lifecycle Hooks
```javascript
imageStory({
getStory: async (index) => {
const response = await fetch(`/api/stories/${index}`);
const data = await response.json();
return {
content: data.html,
onLoad: () => {
console.log(`Story ${index} loaded`);
// Track analytics
gtag('event', 'story_view', { story_id: index });
},
onUnload: () => {
console.log(`Story ${index} unloaded`);
// Cleanup any event listeners
},
};
},
});
```
### With Static Stories
```javascript
const stories = [
{
title: 'Sunset at the Beach',
content: 'A beautiful evening captured at the coast...',
},
{
title: 'Mountain Peak',
content: 'Hiking adventure to the summit...',
},
];
imageStory({
getStory: async (index) => ({
content: `
${stories[index].title}
${stories[index].content}
`,
}),
});
```
## Styling
The extension includes default styles, but you can customize:
```css
/* Story container */
.vvw-story {
/* Positioned at bottom of lightbox */
}
/* Story text area */
.vvw-story-text {
background: rgba(0, 0, 0, 0.8);
backdrop-filter: blur(10px);
color: white;
padding: 16px;
border-radius: 8px;
}
/* Expanded state */
.vvw-story-text.expanded {
max-height: 400px;
overflow-y: auto;
}
/* Expand/collapse button */
.vvw-story-button {
background: rgba(255, 255, 255, 0.1);
border: none;
color: white;
cursor: pointer;
}
```
## Security
The extension automatically sanitizes HTML content using DOMPurify to prevent XSS attacks. However, you should still:
1. **Validate input** on your server
2. **Use Content Security Policy** (CSP) headers
3. **Sanitize user-generated content** before storing
## Performance
### Caching
Stories are cached in memory to avoid redundant API calls:
```javascript
imageStory({
getStory: async (index) => {
// This is only called once per image (until cache eviction)
return await fetchStory(index);
},
maxStoryCache: 10, // Adjust based on memory constraints
});
```
### Lazy Loading
Stories are only fetched when the user navigates to an image, not during initialization.
### Cache Eviction
When the cache exceeds `maxStoryCache`, the oldest entries are evicted (FIFO).
## Bundle Size
- **ESM:** 33.60 KB (10.84 KB gzip)
- **UMD:** 25.28 KB (9.81 KB gzip)
- **CSS:** 2.52 KB (0.72 KB gzip)
Note: Includes DOMPurify for HTML sanitization.
## Next Steps
- Learn about [creating custom extensions](/extensions/authoring)
- Explore other [extensions](/extensions/overview)
- See [configuration options](/core/configuration/complete)
---
# Google Maps Extension
Embed interactive Google Maps in the lightbox
Path: /extensions/google-maps
The Google Maps extension allows you to embed interactive Google Maps in the VistaView lightbox. It displays a static image initially, then loads an interactive iframe embed when opened.
## Installation
### ESM (Module Bundlers)
```javascript
import { vistaView } from 'vistaview';
import { googleMaps } from 'vistaview/extensions/google-maps';
import 'vistaview/style.css';
vistaView({
elements: '#gallery > a',
extensions: [googleMaps()],
});
```
### UMD (CDN)
```html
```
## Requirements
**No API key required** for basic functionality. The extension uses Google Maps' free iframe embed for the interactive map.
An API key is **only needed** if you want to auto-generate static map thumbnails when no `` tag is provided (using Google Maps Static API).
## Configuration
All configuration options are optional:
### apiKey
Your Google Maps API key. **Required to use the Google Maps Static API for generating static map images.** The `getGoogleMapsStaticImage` function uses this to create Static API URLs. The extension will also use this to generate an image if the origin thumbnail image is not available.
```javascript
googleMaps({
apiKey: 'YOUR_GOOGLE_MAPS_API_KEY',
});
```
### zoom
Default zoom level for auto-generated thumbnails (1-20). Default: `15`.
### width
Width for auto-generated thumbnails in pixels. Default: `800`.
### height
Height for auto-generated thumbnails in pixels. Default: `600`.
### mapType
Map type for auto-generated thumbnails: `'roadmap'`, `'satellite'`, `'hybrid'`, or `'terrain'`. Default: `'roadmap'`.
## Usage
### Basic Usage (Recommended)
Provide your own thumbnail images - no API key needed:
```html
```
### Generate Static Map Thumbnails
Use `getGoogleMapsStaticImage` to create Google Maps Static API thumbnail URLs:
```javascript
import {
getGoogleMapsStaticImage,
parseGoogleMapsLocation,
} from 'vistaview/extensions/google-maps';
// Parse the Google Maps URL
const url = 'https://www.google.com/maps/@40.7580,-73.9855,15z';
const location = parseGoogleMapsLocation(url);
// Generate static map image URL
const staticImageUrl = getGoogleMapsStaticImage(location, {
apiKey: 'YOUR_API_KEY',
zoom: 15,
width: 800,
height: 600,
mapType: 'roadmap',
});
console.log(staticImageUrl);
// https://maps.googleapis.com/maps/api/staticmap?center=40.7580,-73.9855&zoom=15&size=800x600&maptype=roadmap&markers=color:red|40.7580,-73.9855&key=YOUR_API_KEY
```
Then use the generated URL in your HTML:
```html
```
## Supported URL Formats
The extension automatically parses various Google Maps URL formats:
### Coordinate Format (@lat,lng,zoom)
```
https://www.google.com/maps/@40.7580,-73.9855,15z
```
### Query Parameter (q=lat,lng or q=place)
```
https://www.google.com/maps?q=40.7580,-73.9855
https://www.google.com/maps?q=Empire+State+Building
```
### LL Parameter (ll=lat,lng)
```
https://maps.google.com?ll=40.7580,-73.9855
```
### Short URLs
```
https://goo.gl/maps/example
```
## Features
- **Free interactive maps** - Uses Google Maps iframe embed (no API key needed)
- **Static previews** - Shows thumbnail image before loading interactive map
- **Smooth transitions** - Fades from static to interactive (1s ease)
- **Pulsing animation** - Loading indicator while iframe loads
- **Responsive sizing** - Maps adapt to lightbox size (16:9 aspect ratio, max 800px width)
- **Full map features** - All Google Maps functionality (zoom, pan, street view, etc.)
- **UI integration** - Automatically disables download and zoom buttons
## How It Works
1. **Initial display**: Shows thumbnail image (from `` tag or auto-generated with API key)
2. **On open**: Loads Google Maps iframe embed in background
3. **Transition**: Fades from static image to interactive map when loaded
4. **Interaction**: Full Google Maps functionality available
## Mixing Content Types
You can mix images and Google Maps in the same gallery:
```html
```
## Bundle Size
- **ESM:** ~3.5 KB (minified)
- **UMD:** ~12 KB (minified)
No external dependencies - the extension uses native iframe embeds.
## API Key Setup (Optional)
**Only needed if you want auto-generated thumbnails.**
1. Go to [Google Cloud Console](https://console.cloud.google.com/)
2. Create or select a project
3. Enable **Maps Static API**
4. Create an API key
5. Restrict the key:
- **Application restrictions**: HTTP referrers (your domain)
- **API restrictions**: Maps Static API only
## Pricing
- **Interactive maps (iframe)**: **FREE** - unlimited usage
- **Static thumbnails (when auto-generated)**: Subject to [Google Maps Static API pricing](https://mapsplatform.google.com/pricing/)
- Free tier: 28,000 static map loads/month
- After free tier: $2.00 per 1,000 loads
💡 **Tip**: Use your own thumbnail images to avoid Static API costs entirely.
## Example: Travel Photo Gallery
```html
```
## Troubleshooting
### Map not opening
- Verify the URL is a valid Google Maps URL
- Check browser console for errors
### Static thumbnail not showing (with API key)
- Ensure Maps Static API is enabled in Google Cloud Console
- Verify API key is correct
- Check API key restrictions aren't blocking requests
- Check browser console for error messages
### No thumbnail showing (without API key, without ``)
This is expected behavior. Either:
- Add `` tags with your own thumbnails (recommended)
- Provide an API key to auto-generate thumbnails
## Related Extensions
- [Mapbox](/extensions/mapbox) - Mapbox GL JS maps
- [OpenStreetMap](/extensions/openstreetmap) - OpenStreetMap embeds
- [YouTube Video](/extensions/youtube-video) - Embed YouTube videos
---
# Logger Extension
Debug extension that logs all lifecycle events
Path: /extensions/logger
The Logger extension is a development tool that logs all lifecycle events to the browser console. It's useful for debugging and understanding the extension system.
## Installation
### ESM (Module Bundlers)
```javascript
import { vistaView } from 'vistaview';
import { logger } from 'vistaview/extensions/logger';
import 'vistaview/style.css';
vistaView({
elements: '#gallery > a',
extensions: [logger()],
});
```
### UMD (CDN)
```html
```
## Features
- **Lifecycle logging** - Logs all extension lifecycle events
- **Image initialization** - Logs when images are initialized
- **Navigation tracking** - Logs image view events
- **Open/close tracking** - Logs lightbox open and close events
- **Console output** - All logs use `console.debug()` for easy filtering
## What Gets Logged
The logger uses `console.debug()` for all output. Each hook logs a label string followed by the raw data object on a second line.
### onInitializeImage
Logged once per image during setup:
```
Logger: VistaView initialized with params:
VistaImageParams { elm: {...}, pos: 0, index: 0, ... }
```
### onOpen
Logged when the lightbox opens:
```
Logger: VistaView opened
VistaView { state: {...}, options: {...}, ... }
```
### onImageView
Logged when navigating to an image:
```
Logger: Image viewed
VistaData { index: { from: 0, to: 1 }, via: { next: true, prev: false }, ... }
```
### onContentChange
Logged when image content changes (pan, zoom, etc.):
```
Logger: Content changed
VistaImageClone { config: {...}, state: { transform: {...} }, ... }
```
### onClose
Logged when the lightbox closes:
```
Logger: VistaView closed
VistaView { state: {...}, options: {...}, ... }
```
## Usage Example
```javascript
import { vistaView } from 'vistaview';
import { logger } from 'vistaview/extensions/logger';
import 'vistaview/style.css';
vistaView({
elements: '#gallery > a',
extensions: [logger()],
onOpen: () => {
console.log('App: Gallery opened');
},
});
```
Open your browser's developer console and interact with the lightbox to see the logs.
## Filtering Logs
The logger uses `console.debug()`, so you can filter logs in your browser's developer console:
### Chrome/Edge
1. Open DevTools (F12)
2. Go to Console tab
3. Select log levels and choose "Verbose" or "Debug"
### Firefox
1. Open Developer Tools (F12)
2. Go to Console tab
3. Click the filter icon and enable "Debug"
### Safari
1. Open Web Inspector (Cmd+Option+I)
2. Go to Console tab
3. Click the filter icon and enable "Debug"
## Bundle Size
- **ESM:** 0.61 KB (0.23 KB gzip)
- **UMD:** 0.76 KB (0.37 KB gzip)
## Use Cases
### Debugging Custom Extensions
```javascript
import { logger } from 'vistaview/extensions/logger';
import { myCustomExtension } from './my-extension';
vistaView({
elements: '#gallery > a',
extensions: [
logger(), // Log all events
myCustomExtension(), // Your extension
],
});
```
### Understanding Event Order
Use the logger to understand the order of lifecycle events:
```javascript
vistaView({
elements: '#gallery > a',
extensions: [logger()],
});
```
Then interact with the lightbox and observe the console:
```
Logger: VistaView opened
Logger: VistaView initialized with params:
Logger: Image viewed
Logger: Image viewed
Logger: VistaView closed
```
### Development vs Production
Only include the logger in development:
```javascript
const extensions = [];
if (process.env.NODE_ENV === 'development') {
const { logger } = await import('vistaview/extensions/logger');
extensions.push(logger());
}
vistaView({
elements: '#gallery > a',
extensions,
});
```
## Next Steps
- Learn about [creating custom extensions](/extensions/authoring)
- Explore other [extensions](/extensions/overview)
- See [events and lifecycle](/core/configuration/events)
---
# Vimeo Video Extension
Embed Vimeo videos in the lightbox
Path: /extensions/vimeo-video
The Vimeo Video extension allows you to embed Vimeo videos in the VistaView lightbox instead of images.
## Installation
### ESM (Module Bundlers)
```javascript
import { vistaView } from 'vistaview';
import { vimeoVideo } from 'vistaview/extensions/vimeo-video';
import 'vistaview/style.css';
vistaView({
elements: '#gallery > a',
extensions: [vimeoVideo()],
});
```
### UMD (CDN)
```html
```
## Usage
Create links pointing to Vimeo video URLs:
```html
```
## Automatic Thumbnail Generation
The extension provides helper functions to generate Vimeo thumbnail URLs from video URLs:
```javascript
import { getVimeoThumbnail, parseVimeoVideoId } from 'vistaview/extensions/vimeo-video';
// Generate thumbnail URL from video URL
const thumbnailUrl = getVimeoThumbnail('https://vimeo.com/123456789');
// Returns: "https://vumbnail.com/123456789.jpg"
// Or extract just the video ID
const videoId = parseVimeoVideoId('https://vimeo.com/123456789');
// Returns: "123456789"
```
:::tip[Vimeo Thumbnail Note]
Vimeo doesn't provide direct thumbnail URLs without API authentication. The `getVimeoThumbnail()` function uses vumbnail.com as a workaround. For production use, consider using [Vimeo's oEmbed API](https://developer.vimeo.com/api/oembed) for more reliable thumbnails.
:::
## Complete Example
```html
```
## Supported URL Formats
The extension automatically detects and parses these Vimeo URL formats:
- `https://vimeo.com/VIDEO_ID`
- `https://player.vimeo.com/video/VIDEO_ID`
- `https://www.vimeo.com/VIDEO_ID`
## Features
- **Autoplay** - Videos automatically start playing when opened
- **Responsive sizing** - Videos maintain 16:9 aspect ratio
- **Full controls** - All Vimeo player controls available
- **High quality** - Videos play at the best available quality
## Mixing Images and Videos
You can mix images and Vimeo videos in the same gallery:
```html
```
## Video Size
The extension creates videos with a maximum width of 800px (or window width, whichever is smaller) while maintaining a 16:9 aspect ratio.
## Bundle Size
- **ESM:** 2.65 KB (1.24 KB gzip)
- **UMD:** 13.69 KB (4.19 KB gzip)
## Privacy Considerations
This extension embeds Vimeo videos using the standard Vimeo player. The player may use cookies and track user interactions according to Vimeo's privacy policy.
## Limitations
- **No zoom controls** - Videos cannot be zoomed like images
- **Requires internet connection** - Videos stream from Vimeo
- **Vimeo Terms of Service** - Ensure compliance with Vimeo's ToS
- **Private videos** - Requires proper authentication/permissions
## Example with Multiple Extensions
```javascript
import { vistaView } from 'vistaview';
import { youtubeVideo } from 'vistaview/extensions/youtube-video';
import { vimeoVideo } from 'vistaview/extensions/vimeo-video';
vistaView({
elements: '#gallery > a',
extensions: [youtubeVideo(), vimeoVideo()],
});
```
## Next Steps
- Try other video extensions: [YouTube](/extensions/youtube-video), [Dailymotion](/extensions/dailymotion-video)
- Learn about [creating custom extensions](/extensions/authoring)
- Explore other [extensions](/extensions/overview)
---
# YouTube Video Extension
Embed YouTube videos in the lightbox
Path: /extensions/youtube-video
The YouTube Video extension allows you to embed YouTube videos in the VistaView lightbox instead of images.
## Installation
### ESM (Module Bundlers)
```javascript
import { vistaView } from 'vistaview';
import { youtubeVideo } from 'vistaview/extensions/youtube-video';
import 'vistaview/style.css';
vistaView({
elements: '#gallery > a',
extensions: [youtubeVideo()],
});
```
### UMD (CDN)
```html
```
## Usage
Create links pointing to YouTube video URLs:
```html
```
## Automatic Thumbnail Generation
The extension provides a helper function to generate YouTube thumbnail URLs from video URLs:
```javascript
import { getYouTubeThumbnail } from 'vistaview/extensions/youtube-video';
// Generate thumbnail URL from video URL
const thumbnailUrl = getYouTubeThumbnail('https://www.youtube.com/watch?v=dQw4w9WgXcQ');
// Returns: "https://img.youtube.com/vi/dQw4w9WgXcQ/hqdefault.jpg"
// Use in your gallery dynamically
const videoUrl = 'https://youtu.be/dQw4w9WgXcQ';
const link = document.createElement('a');
link.href = videoUrl;
const img = document.createElement('img');
img.src = getYouTubeThumbnail(videoUrl);
img.alt = 'Video thumbnail';
link.appendChild(img);
document.getElementById('gallery').appendChild(link);
```
You can also extract just the video ID:
```javascript
import { parseYouTubeVideoId } from 'vistaview/extensions/youtube-video';
const videoId = parseYouTubeVideoId('https://www.youtube.com/watch?v=dQw4w9WgXcQ');
// Returns: "dQw4w9WgXcQ"
```
## Complete Example
```html
```
## Supported URL Formats
The extension automatically detects and parses these YouTube URL formats:
- `https://www.youtube.com/watch?v=VIDEO_ID`
- `https://youtu.be/VIDEO_ID`
- `https://www.youtube.com/embed/VIDEO_ID`
- `https://m.youtube.com/watch?v=VIDEO_ID`
## Features
- **Autoplay** - Videos automatically start playing when opened
- **Responsive sizing** - Videos maintain 16:9 aspect ratio
- **Full controls** - All YouTube player controls available
- **No related videos from other channels** - `rel=0` parameter set by default
## Mixing Images and Videos
You can mix images and YouTube videos in the same gallery:
```html
```
## Video Size
The extension creates videos with a maximum width of 800px (or window width, whichever is smaller) while maintaining a 16:9 aspect ratio.
## Customization
### Custom Video Size
Extend the extension to customize video dimensions:
```javascript
import { youtubeVideo } from 'vistaview/extensions/youtube-video';
// The extension uses fixed sizing, but you can create a custom version
// See the Extensions Authoring Guide for details
```
### Styling
The video iframe uses the class `vvw-img-hi` and can be styled:
```css
.vvw-img-hi {
border-radius: 8px;
box-shadow: 0 0 40px rgba(0, 0, 0, 0.5);
}
```
## Bundle Size
- **ESM:** 3.10 KB (1.42 KB gzip)
- **UMD:** 14.07 KB (4.36 KB gzip)
## Privacy Considerations
This extension embeds YouTube videos using the standard `youtube.com` domain. For enhanced privacy, you may want to create a custom extension using `youtube-nocookie.com` domain.
## Limitations
- **No zoom controls** - Videos cannot be zoomed like images
- **Requires internet connection** - Videos stream from YouTube
- **YouTube Terms of Service** - Ensure compliance with YouTube's ToS
## Example with Multiple Extensions
```javascript
import { vistaView } from 'vistaview';
import { youtubeVideo } from 'vistaview/extensions/youtube-video';
import { vimeoVideo } from 'vistaview/extensions/vimeo-video';
import { download } from 'vistaview/extensions/download';
vistaView({
elements: '#gallery > a',
extensions: [
youtubeVideo(),
vimeoVideo(),
download(), // Works for images, not videos
],
});
```
## Next Steps
- Try other video extensions: [Vimeo](/extensions/vimeo-video), [Dailymotion](/extensions/dailymotion-video)
- Learn about [creating custom extensions](/extensions/authoring)
- Explore other [extensions](/extensions/overview)
---
# Wistia Video Extension
Embed Wistia videos in the lightbox
Path: /extensions/wistia-video
The Wistia Video extension allows you to embed Wistia videos in the VistaView lightbox instead of images.
## Installation
### ESM (Module Bundlers)
```javascript
import { vistaView } from 'vistaview';
import { wistiaVideo } from 'vistaview/extensions/wistia-video';
import 'vistaview/style.css';
vistaView({
elements: '#gallery > a',
extensions: [wistiaVideo()],
});
```
### UMD (CDN)
```html
```
## Usage
Create links pointing to Wistia video URLs:
```html
```
## Automatic Thumbnail Generation
The extension provides helper functions to work with Wistia video URLs:
```javascript
import { getWistiaThumbnail, parseWistiaVideoId } from 'vistaview/extensions/wistia-video';
// Extract video ID
const videoId = parseWistiaVideoId('https://fast.wistia.net/embed/iframe/abc123def');
// Returns: "abc123def"
// Get thumbnail URL (async - fetches from Wistia's oEmbed API)
const thumbnailUrl = await getWistiaThumbnail('https://fast.wistia.net/embed/iframe/abc123def');
// Returns: URL to the video thumbnail
```
:::tip[Wistia Thumbnail Note]
The `getWistiaThumbnail()` function is **async** because it fetches thumbnail information from Wistia's oEmbed API. Make sure to use `await` or handle the Promise appropriately.
:::
## Complete Example
```html
```
## Supported URL Formats
The extension automatically detects and parses Wistia video URLs containing video IDs.
## Features
- **Autoplay** - Videos automatically start playing when opened
- **Responsive sizing** - Videos maintain 16:9 aspect ratio
- **Full controls** - All Wistia player controls available
- **High quality** - Videos play at the best available quality
## Video Size
The extension creates videos with a maximum width of 800px (or window width, whichever is smaller) while maintaining a 16:9 aspect ratio.
## Bundle Size
- **ESM:** 2.93 KB (1.35 KB gzip)
- **UMD:** 13.92 KB (4.28 KB gzip)
## Limitations
- **No zoom controls** - Videos cannot be zoomed like images
- **Requires internet connection** - Videos stream from Wistia
- **Wistia account required** - Videos must be hosted on Wistia
## Next Steps
- Try other video extensions: [YouTube](/extensions/youtube-video), [Vimeo](/extensions/vimeo-video)
- Learn about [creating custom extensions](/extensions/authoring)
- Explore other [extensions](/extensions/overview)
---
# Behavior Extensions
Create extensions that add functionality without visible UI
Path: /extensions/authoring/behavior-extensions
Behavior extensions add functionality through lifecycle hooks without adding visible controls. They're perfect for logging, analytics, keyboard shortcuts, and other non-visual features.
## Basic Behavior Extension
```typescript
import type { VistaExtension } from 'vistaview';
export function simpleLogger(): VistaExtension {
return {
name: 'simpleLogger',
onOpen: () => console.log('Opened'),
onClose: () => console.log('Closed'),
};
}
```
## Complete Example: Logger
A comprehensive logging extension:
```typescript
import type { VistaData, VistaExtension, VistaImageClone, VistaImageParams } from 'vistaview';
import type { VistaView } from 'vistaview';
export function logger(): VistaExtension {
return {
name: 'logger',
onInitializeImage: (params: VistaImageParams) => {
console.debug('Logger: VistaView initialized with params:');
console.debug(params);
},
onContentChange: (_content: VistaImageClone, _v: VistaView) => {
console.debug('Logger: Content changed');
console.debug(_content);
},
onImageView: async (vistaData: VistaData, _v: VistaView) => {
console.debug('Logger: Image viewed');
console.debug(vistaData);
},
onOpen: async (_vistaView: VistaView) => {
console.debug('Logger: VistaView opened');
console.debug(_vistaView);
},
onClose: (_vistaView: VistaView) => {
console.debug('Logger: VistaView closed');
console.debug(_vistaView);
},
};
}
```
## Analytics Extension
Track user interactions:
```typescript
import type { VistaData, VistaExtension, VistaView } from 'vistaview';
export function analytics({
trackEvent,
}: {
trackEvent: (event: string, data: any) => void;
}): VistaExtension {
let openTime: number;
let viewCount = 0;
return {
name: 'analytics',
onOpen: (vistaView: VistaView) => {
openTime = Date.now();
viewCount = 0;
trackEvent('lightbox_open', {
totalImages: vistaView.state.elmLength,
});
},
onImageView: (vistaData: VistaData, _v: VistaView) => {
viewCount++;
trackEvent('image_view', {
index: vistaData.index.to,
viewNumber: viewCount,
});
},
onClose: (_v: VistaView) => {
const duration = Date.now() - openTime;
trackEvent('lightbox_close', {
duration,
imagesViewed: viewCount,
averageTimePerImage: duration / viewCount,
});
},
};
}
```
Usage:
```typescript
vistaView({
elements: '#gallery > a',
extensions: [
analytics({
trackEvent: (event, data) => {
// Send to your analytics service
gtag('event', event, data);
},
}),
],
});
```
## Keyboard Shortcuts Extension
Add custom keyboard shortcuts:
```typescript
import type { VistaExtension, VistaView } from 'vistaview';
export function keyboardShortcuts(): VistaExtension {
let vistaView: VistaView | null = null;
const handleKeyDown = (e: KeyboardEvent) => {
if (!vistaView) return;
switch (e.key) {
case 'f':
// Toggle fullscreen
if (document.fullscreenElement) {
document.exitFullscreen();
} else {
document.documentElement.requestFullscreen();
}
break;
case 'd':
// Download current image
// Trigger download logic
break;
case 'i':
// Show image info
console.log(vistaView.state);
break;
}
};
return {
name: 'keyboardShortcuts',
onOpen: (view: VistaView) => {
vistaView = view;
document.addEventListener('keydown', handleKeyDown);
},
onClose: () => {
document.removeEventListener('keydown', handleKeyDown);
vistaView = null;
},
};
}
```
## Preload Adjacent Images
**Note:** VistaView already handles image preloading internally. This example is provided for educational purposes to demonstrate behavior extension patterns.
```typescript
import type { VistaData, VistaExtension } from 'vistaview';
export function preloadAdjacent(): VistaExtension {
const preloadCache = new Map();
const preload = (src: string) => {
if (preloadCache.has(src)) return;
const img = new Image();
img.src = src;
preloadCache.set(src, img);
};
return {
name: 'preloadAdjacent',
onImageView: (vistaData: VistaData, vistaView: VistaView) => {
const currentIndex = vistaData.index.to ?? 0;
const total = vistaView.state.elmLength;
// Preload next image
const nextIndex = (currentIndex + 1) % total;
const nextImage = vistaView.state.children.images[nextIndex];
if (nextImage?.config.src) {
preload(nextImage.config.src);
}
// Preload previous image
const prevIndex = (currentIndex - 1 + total) % total;
const prevImage = vistaView.state.children.images[prevIndex];
if (prevImage?.config.src) {
preload(prevImage.config.src);
}
},
onClose: () => {
preloadCache.clear();
},
};
}
```
## Auto-Play Slideshow
Automatic image rotation:
```typescript
import type { VistaExtension, VistaView } from 'vistaview';
export function autoPlay({
interval = 3000,
}: {
interval?: number;
} = {}): VistaExtension {
let intervalId: number | null = null;
let vistaView: VistaView | null = null;
const startAutoPlay = () => {
if (intervalId) return;
intervalId = window.setInterval(() => {
if (!vistaView) return;
const currentIndex = vistaView.state.currentIndex;
const total = vistaView.state.elmLength;
const nextIndex = (currentIndex + 1) % total;
vistaView.view(nextIndex);
}, interval);
};
const stopAutoPlay = () => {
if (intervalId !== null) {
clearInterval(intervalId);
intervalId = null;
}
};
return {
name: 'autoPlay',
onOpen: (view: VistaView) => {
vistaView = view;
startAutoPlay();
},
onImageView: () => {
// Reset timer on manual navigation
stopAutoPlay();
startAutoPlay();
},
onClose: () => {
stopAutoPlay();
vistaView = null;
},
};
}
```
## Image Counter Display
Show current position without adding a control:
```typescript
import type { VistaData, VistaExtension, VistaView } from 'vistaview';
export function imageCounter(): VistaExtension {
let counterElement: HTMLDivElement | null = null;
return {
name: 'imageCounter',
onOpen: (vistaView: VistaView) => {
counterElement = document.createElement('div');
counterElement.className = 'vvw-counter';
counterElement.style.cssText = `
position: absolute;
top: 20px;
left: 50%;
transform: translateX(-50%);
background: var(--vvw-ui-bg-color);
color: var(--vvw-ui-text-color);
padding: 8px 16px;
border-radius: var(--vvw-ui-border-radius);
font-size: 14px;
`;
vistaView.qs('.vvw-container')?.appendChild(counterElement);
},
onImageView: (vistaData: VistaData, vistaView: VistaView) => {
const current = (vistaData.index.to ?? 0) + 1;
const total = vistaView.state.elmLength;
if (counterElement) {
counterElement.textContent = `${current} / ${total}`;
}
},
onClose: () => {
counterElement?.remove();
counterElement = null;
},
};
}
```
## Key Concepts
### Lifecycle Hooks
Behavior extensions use lifecycle hooks to react to events:
- `onOpen` - Lightbox opened, set up state
- `onImageView` - Image changed, update based on new image
- `onClose` - Lightbox closed, clean up resources
### State Persistence
Use closure variables to maintain state:
```typescript
export function statefulExtension(): VistaExtension {
let count = 0;
let cache = new Map();
return {
name: 'statefulExtension',
onImageView: () => {
count++; // Persists between calls
},
};
}
```
### Cleanup
Always clean up resources:
```typescript
onClose: () => {
clearInterval(intervalId);
document.removeEventListener('keydown', handler);
cache.clear();
vistaView = null;
};
```
## Next Steps
- [Content Extensions](/extensions/authoring/content-extensions)
- [Built-in Extensions](/extensions/overview)
---
# UI Extensions
Create extensions that add visible controls to the lightbox
Path: /extensions/authoring/ui-extensions
UI extensions add visible controls to the lightbox interface. They provide the `control` method that returns an HTML element to be added to the UI.
## Basic UI Extension
```typescript
import type { VistaExtension } from 'vistaview';
export function myButton(): VistaExtension {
return {
name: 'myButton',
control: () => {
const button = document.createElement('button');
button.setAttribute('aria-label', 'My Button');
button.textContent = '✨';
button.addEventListener('click', () => {
console.log('Button clicked!');
});
return button;
},
};
}
```
## Complete Example: Download Button
A fully-featured download button with state management:
```typescript
import type { VistaData, VistaExtension, VistaView } from 'vistaview';
const downloadIcon = ``;
export function download(): VistaExtension {
let currentImage: string | null = null;
let currentAlt: string | null = null;
let button: HTMLButtonElement | null = null;
return {
name: 'download',
control: () => {
button = document.createElement('button');
button.setAttribute('aria-label', 'Download');
button.innerHTML = downloadIcon;
button.addEventListener('click', async () => {
if (!currentImage) return;
if (button?.classList.contains('vvw--pulsing')) return; // prevent multiple clicks
button?.classList.add('vvw--pulsing');
let response: Response | null = await fetch(currentImage);
let blob: Blob | null = await response.blob();
const finalUrl = response.url; // This is the redirected URL
const alt = currentAlt;
const extension = finalUrl.split('?')[0].split('#')[0].split('.').pop();
const fileName = alt
? `${alt}.${extension}`
: finalUrl.split('?')[0].split('#')[0].split('/').pop() || 'download.' + extension;
const link = document.createElement('a');
link.href = URL.createObjectURL(blob);
link.download = fileName;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
blob = null;
response = null;
button?.classList.remove('vvw--pulsing');
});
return button;
},
onImageView: (vistaData: VistaData, _v: VistaView) => {
const centerImage = vistaData.images.to
? vistaData.images.to[Math.floor(vistaData.images.to.length / 2)]
: null;
if (!centerImage) {
currentImage = null;
currentAlt = null;
return;
}
const { parsedSrcSet, config } = centerImage;
// get the biggest image || the current image
currentImage =
parsedSrcSet && parsedSrcSet.length > 0
? parsedSrcSet[parsedSrcSet.length - 1].src
: config.src || null;
currentAlt = config.alt || null;
},
onDeactivateUi: (names: string[], _requestBy, _v: VistaView) => {
if (names.includes('download') && button) {
button.setAttribute('disabled', 'true');
}
},
onReactivateUi: (names: string[], _requestBy, _v: VistaView) => {
if (names.includes('download') && button) {
button.removeAttribute('disabled');
}
},
onClose: (_v: VistaView) => {
button?.remove();
button = null;
currentImage = null;
currentAlt = null;
},
};
}
```
## Adding the Control to UI
Specify where your control appears using the `controls` config:
```typescript
vistaView({
elements: '#gallery > a',
controls: {
topRight: ['zoomIn', 'zoomOut', 'download', 'close'],
},
extensions: [download()],
});
```
Available positions:
- `topLeft`
- `topRight`
- `bottomLeft`
- `bottomRight`
## UI Extension with SVG Icons
```typescript
export function fullscreen(): VistaExtension {
const enterIcon = ``;
const exitIcon = ``;
let button: HTMLButtonElement | null = null;
let isFullscreen = false;
return {
name: 'fullscreen',
control: () => {
button = document.createElement('button');
button.setAttribute('aria-label', 'Toggle fullscreen');
button.innerHTML = enterIcon;
button.addEventListener('click', async () => {
if (!isFullscreen) {
await document.documentElement.requestFullscreen();
button!.innerHTML = exitIcon;
} else {
await document.exitFullscreen();
button!.innerHTML = enterIcon;
}
isFullscreen = !isFullscreen;
});
return button;
},
onClose: () => {
if (isFullscreen) {
document.exitFullscreen();
}
button?.remove();
button = null;
isFullscreen = false;
},
};
}
```
## Styling UI Extensions
Use CSS variables for consistent styling:
```css
.vvw-ui button[aria-label='Download'] {
background: var(--vvw-ui-bg-color);
color: var(--vvw-ui-text-color);
border-radius: var(--vvw-ui-border-radius);
padding: 8px;
border: none;
cursor: pointer;
}
.vvw-ui button[aria-label='Download']:hover {
background: var(--vvw-ui-hover-bg-color);
}
.vvw-ui button[aria-label='Download']:disabled {
opacity: 0.5;
cursor: not-allowed;
}
```
## Key Concepts
### State Management
Use closure variables to persist state:
```typescript
export function myExtension(): VistaExtension {
let button: HTMLButtonElement | null = null;
let currentState = 'idle';
return {
name: 'myExtension',
control: () => {
button = document.createElement('button');
// Use button and currentState throughout lifecycle
return button;
},
};
}
```
### Cleanup
Always clean up in `onClose`:
```typescript
onClose: () => {
button?.removeEventListener('click', handleClick);
button?.remove();
button = null;
currentImage = null;
};
```
### UI State
Handle disable/enable states. Your Extensions might not be known to other extensions.
If you want your extensions to have the same state as the zoomIn, zoomOut, and download extension, check for 'zoomIn', 'zoomOut', or 'download'.
For example, Video extensions disable the download button by default, so your extensions might want to listen to the download 'button' as well:
```typescript
onDeactivateUi: (names) => {
if ((names.includes('myExtension') || names.includes('download')) && button) {
button.setAttribute('disabled', 'true');
button.classList.add('disabled');
}
},
onReactivateUi: (names) => {
if ((names.includes('myExtension') || names.includes('download')) && button) {
button.removeAttribute('disabled');
button.classList.remove('disabled');
}
}
```
## Next Steps
- [Behavior Extensions](/extensions/authoring/behavior-extensions)
- [Built-in Extensions](/extensions/overview)
---
# Extensions Authoring Guide
Learn how to create custom extensions for VistaView
Path: /extensions/authoring
Extensions are objects that implement the `VistaExtension` interface and hook into the lightbox lifecycle. You pass them in the `extensions` array when initializing VistaView, and they can add UI controls, respond to navigation events, replace image rendering with custom content, and more.
## The VistaExtension Interface
```typescript
import type {
VistaExtension,
VistaImageParams,
VistaData,
VistaImageClone,
VistaView,
VistaBox,
} from 'vistaview';
const myExtension: VistaExtension = {
// Required: unique name used to reference this extension in controls config
name: 'myExtension',
// Optional: shown in aria-label when the extension provides a control
description: 'My custom extension',
// Optional: return an HTMLElement to add to the UI toolbar
control: () => { /* ... */ return button; },
// Optional: intercept image initialization — return a VistaBox to replace default image
onInitializeImage: (params: VistaImageParams) => { /* ... */ },
// Optional: called when the lightbox opens
onOpen: (vistaView: VistaView) => { /* ... */ },
// Optional: called when navigating to an image
onImageView: (data: VistaData, vistaView: VistaView) => { /* ... */ },
// Optional: called when image content changes (pan, zoom, etc.)
onContentChange: (content: VistaImageClone, vistaView: VistaView) => { /* ... */ },
// Optional: called when UI controls are disabled (e.g. video is shown)
onDeactivateUi: (names: string[], requestBy: VistaBox | null, vistaView: VistaView) => { /* ... */ },
// Optional: called when UI controls are re-enabled
onReactivateUi: (names: string[], requestBy: VistaBox | null, vistaView: VistaView) => { /* ... */ },
// Optional: called when the lightbox closes
onClose: (vistaView: VistaView) => { /* ... */ },
};
```
## Quick Start
The minimal extension — just a name and one hook:
```typescript
import type { VistaExtension } from 'vistaview';
import { vistaView } from 'vistaview';
export function myExtension(): VistaExtension {
return {
name: 'myExtension',
onOpen: (v) => {
console.log('Lightbox opened, total images:', v.state.elmLength);
},
};
}
vistaView({
elements: '#gallery > a',
extensions: [myExtension()],
});
```
## Extension Types
There are three patterns, each covered in its own guide:
### UI Extensions
Add a button or other control element to the toolbar. The `control()` method returns the element; you register it in the `controls` config by the extension's `name`.
Use `onDeactivateUi` / `onReactivateUi` to respond when other extensions disable controls (for example, video extensions disable zoom and download).
→ [UI Extensions guide](/extensions/authoring/ui-extensions)
### Behavior Extensions
React to lifecycle events without any visible UI — logging, analytics, keyboard shortcuts, auto-play, etc. These only use the `on*` hooks.
→ [Behavior Extensions guide](/extensions/authoring/behavior-extensions)
### Content Extensions
Intercept `onInitializeImage` and return a custom `VistaBox` subclass to replace the default image renderer. Used for videos, maps, iframes, or any non-image content.
→ [Content Extensions guide](/extensions/authoring/content-extensions)
## Lifecycle Event Order
### On open
1. `onOpen` (all extensions)
2. `onInitializeImage` (per image, for preloaded images)
3. `onImageView` (for the initial image)
### On navigate
1. `onInitializeImage` (for newly preloaded images)
2. `onImageView`
### On close
1. `onClose` (all extensions)
## Using Extensions with Controls
If your extension provides a `control()`, register it by name in the `controls` configuration:
```typescript
vistaView({
elements: '#gallery > a',
extensions: [myExtension()],
controls: {
topRight: ['zoomIn', 'zoomOut', 'myExtension', 'close'],
},
});
```
The extension name and the string in the controls array must match exactly.
## Next Steps
- [UI Extensions](/extensions/authoring/ui-extensions) — add buttons and toolbar elements
- [Behavior Extensions](/extensions/authoring/behavior-extensions) — hook into events without UI
- [Content Extensions](/extensions/authoring/content-extensions) — render custom content types
- [Built-in Extensions](/extensions/overview) — see real examples
---
# Content Extensions
Support custom content types by extending VistaBox
Path: /extensions/authoring/content-extensions
Content extensions allow VistaView to display custom content types beyond images. They implement `onInitializeImage` to return custom `VistaBox` instances.
## VistaBox Overview
`VistaBox` is the base class that handles content display, sizing, and transitions. To support custom content:
1. Extend `VistaBox`
2. Set `this.element` to your custom DIV element
3. Define dimensions (`fullW`, `fullH`, `minW`, `maxW`)
4. Override methods as needed
:::tip[VistaBox Source Code]
For a complete understanding of `VistaBox` properties and methods, check the [source code on GitHub](https://github.com/juji/vistaview/blob/main/src/lib/vista-box.ts).
:::
## Basic Content Extension
```typescript
import type { VistaExtension, VistaImageParams } from 'vistaview';
import { VistaBox } from 'vistaview';
class VistaCustomContent extends VistaBox {
element: HTMLDivElement;
constructor(par: VistaImageParams) {
super(par); // Always call super first
// Create your custom element
this.element = document.createElement('div');
this.element.classList.add('vvw-img-hi');
this.element.textContent = 'Custom Content';
// Set dimensions
const { width: fullWidth, height: fullHeight } = this.getFullSizeDim();
this.fullH = fullHeight;
this.fullW = fullWidth;
this.minW = this.fullW * 0.5; // Required: tells VistaView when to close (size threshold)
this.maxW = this.fullW;
this.element.style.width = `${fullWidth}px`;
this.element.style.height = `${fullHeight}px`;
// Initialize sizes
this.setSizes({ stableSize: false, initDimension: true });
// Mark as loaded
this.isLoadedResolved!(true);
}
protected getFullSizeDim(): { width: number; height: number } {
return { width: 800, height: 600 };
}
}
export function customContent(): VistaExtension {
return {
name: 'customContent',
onInitializeImage: (params: VistaImageParams) => {
// Check if this element should use custom content
if (params.elm.config.src.includes('custom')) {
return new VistaCustomContent(params);
}
},
};
}
```
## Video Extension Example
Complete YouTube video extension:
```typescript
import type { VistaData, VistaExtension, VistaImageParams } from 'vistaview';
import { VistaBox } from 'vistaview';
import type { VistaView } from 'vistaview';
export function parseYouTubeVideoId(url: string): string | null {
if (!url) return null;
const patterns = [
/(?:youtube\.com\/watch\?v=|youtu\.be\/)([a-zA-Z0-9_-]{11})/,
/youtube\.com\/embed\/([a-zA-Z0-9_-]{11})/,
/youtube\.com\/v\/([a-zA-Z0-9_-]{11})/,
/youtube\.com\/live\/([a-zA-Z0-9_-]{11})/,
/youtube\.com\/shorts\/([a-zA-Z0-9_-]{11})/,
];
for (const pattern of patterns) {
const match = url.match(pattern);
if (match?.[1]) return match[1];
}
return null;
}
export function getYouTubeThumbnail(videoUrl: string): string {
const videoId = parseYouTubeVideoId(videoUrl);
if (!videoId) throw new Error('Invalid YouTube video URL');
return `https://img.youtube.com/vi/${videoId}/hqdefault.jpg`;
}
export class VistaYoutubeVideo extends VistaBox {
element: HTMLDivElement;
url: string;
constructor(par: VistaImageParams) {
super(par);
const url = par.elm.config.src;
this.url = url;
// Create container with thumbnail
const div = document.createElement('div');
div.style.position = 'relative';
// youtube thumbnail view
// for initial iframe loading
const image = document.createElement('img');
div.appendChild(image);
// Get thumbnail source from:
// 1. Origin image (if lightbox opened from thumbnail click)
// 2. data-thumbnail attribute
// 3. Generated YouTube thumbnail URL
image.src = this.origin?.image.src || par.elm.elm.dataset.thumbnail || getYouTubeThumbnail(url);
image.style.width = '100%';
image.style.height = '100%';
image.style.objectFit = 'cover';
image.classList.add('vvw--pulsing');
// add vvw-img-hi clas to the div
// so the animation will run
this.element = div;
this.element.classList.add('vvw-img-hi');
// Set dimensions
const { width: fullWidth, height: fullHeight } = this.getFullSizeDim();
this.fullH = fullHeight;
this.fullW = fullWidth;
this.minW = this.fullW * 0.5; // Required: tells VistaView when to close (size threshold)
this.maxW = this.fullW;
this.element.style.width = `${fullWidth}px`;
this.element.style.height = `${fullHeight}px`;
// Initialize sizes
// always do this
this.setSizes({ stableSize: false, initDimension: true });
// Load iframe when in center position
if (this.pos === 0) {
const iframe = document.createElement('iframe');
iframe.frameBorder = '0';
iframe.allow =
'accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share';
iframe.allowFullscreen = true;
iframe.width = '100%';
iframe.height = '100%';
iframe.style.position = 'absolute';
iframe.style.top = '0';
iframe.style.left = '0';
iframe.style.backgroundColor = 'transparent';
iframe.style.opacity = '0';
iframe.style.transition = 'opacity 1s ease';
iframe.src = `https://www.youtube.com/embed/${parseYouTubeVideoId(url)}?autoplay=1&rel=0`;
div.appendChild(iframe);
iframe.onload = () => {
iframe.style.opacity = '1';
image.classList.remove('vvw--pulsing');
};
}
// set as loaded
this.isLoadedResolved!(true);
}
// for videos, the full size have a max width
// so we extend this function
protected getFullSizeDim(): { width: number; height: number } {
const maxWidth = Math.min(window.innerWidth, 800);
return {
width: maxWidth,
height: (maxWidth * 9) / 16,
};
}
// final transform should not propagate events,
// since we don't need it for videos
setFinalTransform() {
return super.setFinalTransform({ propagateEvent: false });
}
}
export function youtubeVideo(): VistaExtension {
return {
name: 'ytVideo',
onInitializeImage: (params: VistaImageParams) => {
const url = params.elm.config.src;
const videoId = parseYouTubeVideoId(url);
if (!videoId) return;
return new VistaYoutubeVideo(params);
},
onImageView: async (data: VistaData, v: VistaView) => {
const mainData = data.images.to![Math.floor(data.images.to!.length / 2)];
if (mainData instanceof VistaYoutubeVideo) {
// deactivate these on display
v.deactivateUi(['download', 'zoomIn', 'zoomOut'], mainData);
}
},
};
}
```
Usage:
```html
```
```typescript
vistaView({
elements: '#gallery > a',
extensions: [youtubeVideo()],
});
```
## Key Points
### Constructor Requirements
```typescript
constructor(par: VistaImageParams) {
super(par); // ALWAYS call first
// Create your element
this.element = document.createElement('div');
this.element.classList.add('vvw-img-hi');
// Get dimensions
const { width: fullWidth, height: fullHeight } = this.getFullSizeDim();
// Set dimensions
this.fullW = fullWidth;
this.fullH = fullHeight;
this.minW = fullWidth * 0.5;
this.maxW = fullWidth;
// Set element size
this.element.style.width = `${fullWidth}px`;
this.element.style.height = `${fullHeight}px`;
// Initialize
this.setSizes({ stableSize: false, initDimension: true });
// Handle loading
this.isLoadedResolved!(true); // or wait for async load
}
```
### Override Methods
```typescript
// Required: Return full dimensions
protected getFullSizeDim(): { width: number; height: number } {
const maxWidth = Math.min(window.innerWidth, 800);
return {
width: maxWidth,
height: (maxWidth * 9) / 16,
};
}
// Optional: Custom transform behavior
setFinalTransform() {
return super.setFinalTransform({ propagateEvent: false });
}
```
```typescript
constructor(par: VistaImageParams) {
super(par); // ALWAYS call first
// Create your element
this.element = document.createElement('div');
// Set dimensions
this.fullW = 800;
this.fullH = 600;
this.minW = 400;
this.maxW = 1200;
// Initialize
this.setSizes({ stableSize: false, initDimension: true });
// Handle loading
this.isLoadedResolved!(true); // or wait for async load
}
```
**Key Points:**
- `element` must be set in constructor
- Call `getFullSizeDim()` to get dimensions, then apply to `element.style`
- Must call `isLoadedResolved!(true)` when ready
- Can call `isLoadedRejected!(error)` on failure
## Handling Content Detection
Check attributes or URL patterns in `onInitializeImage`:
```typescript
export function myPdfContent(): VistaExtension {
return {
name: 'myPdfContent',
onInitializeImage: (par: VistaImageParams) => {
const url = par.elm.config.src;
const type = par.elm.elm.getAttribute('data-type');
// Check by URL pattern (includes yourpdfsite.com and ends with .pdf)
if (/yourpdfsite\.com.*\.pdf$/i.test(url)) {
return new MyVistaPDF(par);
}
},
};
}
```
## Next Steps
- [Built-in Video Extensions](/extensions/overview)
---
## Styling & Theming
---
# CSS Variables
Customize VistaView appearance with CSS custom properties
Path: /styling/css-variables
VistaView uses CSS custom properties (CSS variables) for easy customization without modifying the source code.
## Basic Usage
Import the base CSS file:
```javascript
import 'vistaview/style.css';
```
Then override variables in your own CSS:
```css
/* The following are default values */
:root {
--vvw-bg-color: #000000;
--vvw-text-color: #ffffff;
--vvw-bg-blur: 10px;
--vvw-bg-opacity: 0.8;
--vvw-anim-dur: 333;
--vvw-init-z: 1;
--vvw-dest-z: 2147483647;
--vvw-ui-outline-color: hsl(from var(--vvw-bg-color) h s calc(l + 30));
--vvw-ui-text-color: var(--vvw-text-color);
--vvw-ui-bg-color: var(--vvw-bg-color);
--vvw-ui-hover-bg-color: hsl(from var(--vvw-bg-color) h s calc(l + 20));
--vvw-ui-active-bg-color: hsl(from var(--vvw-bg-color) h s calc(l + 40));
--vvw-ui-border-radius: 0px;
--vvw-ui-border-width: 0px;
}
```
## Available Variables
### Core Colors
```css
:root {
--vvw-bg-color: #000000;
--vvw-text-color: #ffffff;
--vvw-bg-blur: 10px;
--vvw-bg-opacity: 0.8;
}
```
### Animation
```css
:root {
/* Duration in milliseconds */
--vvw-anim-dur: 333;
}
```
### Z-Index
```css
:root {
/* Initial z-index (set via initialZIndex config) */
--vvw-init-z: 1;
/* Maximum z-index when lightbox is open */
--vvw-dest-z: 2147483647;
}
```
### UI Theme Colors
These are derived from the core colors:
```css
:root {
--vvw-ui-outline-color: hsl(from var(--vvw-bg-color) h s calc(l + 30));
--vvw-ui-bg-color: var(--vvw-bg-color);
--vvw-ui-text-color: var(--vvw-text-color);
--vvw-ui-hover-bg-color: hsl(from var(--vvw-bg-color) h s calc(l + 20));
--vvw-ui-active-bg-color: hsl(from var(--vvw-bg-color) h s calc(l + 40));
--vvw-ui-border-radius: 0px;
--vvw-ui-border-width: 1px;
}
```
## Best Practices
1. **Only override what you need** - Most variables have sensible defaults
2. **Test with different themes** for pre-built options before customizing
3. **Use semantic colors** - The UI colors derive from `--vvw-bg-color` automatically
4. **Consider accessibility** - Ensure adequate contrast ratios
## Next Steps
- Explore [pre-built themes](/styling/themes)
- Learn about [custom styling](/styling/custom)
- See [configuration options](/core/configuration/complete)
---
# Custom Styling
Create custom styles and themes for VistaView
Path: /styling/custom
There are two ways to customize the appearance of VistaView:
1. **Update CSS variables** - Quick customization using existing variables
2. **Create a custom CSS file** - Full theme with custom styling
## Method 1: Update CSS Variables
The simplest way to customize VistaView is by overriding CSS variables in your own stylesheet.
```css
/* custom.css */
:root {
/* Colors */
--vvw-bg-color: #1a1a2e;
--vvw-text-color: #eee;
--vvw-bg-opacity: 0.95;
--vvw-bg-blur: 10px;
/* UI Colors */
--vvw-ui-outline-color: #333;
--vvw-ui-bg-color: #16213e;
--vvw-ui-text-color: #fff;
--vvw-ui-hover-bg-color: #0f3460;
--vvw-ui-active-bg-color: #e94560;
/* UI Styling */
--vvw-ui-border-radius: 12px;
--vvw-ui-border-width: 1px;
}
```
Import after the base styles:
```javascript
import 'vistaview/style.css';
import './custom.css';
```
See the [CSS Variables](/styling/css-variables) reference for all available variables.
## Method 2: Create a Custom Theme
For more control, create a complete custom theme file that includes both variable overrides and custom styling.
```css
/* my-theme.css */
/* Override variables */
:root {
--vvw-bg-color: #1a1a2e;
--vvw-text-color: #eee;
--vvw-ui-bg-color: #16213e;
--vvw-ui-hover-bg-color: #0f3460;
--vvw-ui-border-radius: 12px;
}
/* Custom component styling */
.vvw-ui {
&.vvw-prev,
&.vvw-next {
button {
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
&:hover {
transform: scale(1.1);
}
}
}
}
.vvw-bottom-bar,
.vvw-top-bar {
button {
transition: all 200ms ease;
&:hover {
box-shadow: 0 0 12px var(--vvw-ui-hover-bg-color);
}
}
}
```
Import after the base styles:
```javascript
import 'vistaview/style.css';
import './my-theme.css';
```
## Accessibility Features
### Automatic Reduced Motion Support
VistaView detects the browser's `prefers-reduced-motion` setting and automatically disables slide transitions. This happens at runtime - no CSS configuration needed.
### High Contrast Mode
```css
@media (prefers-contrast: high) {
:root {
--vvw-bg-color: #000;
--vvw-text-color: #fff;
--vvw-ui-bg-color: #000;
--vvw-ui-text-color: #fff;
--vvw-ui-hover-bg-color: #333;
--vvw-ui-border-width: 2px;
}
}
```
## Next Steps
- Review [CSS variables](/styling/css-variables) reference
- Explore [pre-built themes](/styling/themes)
- Check out [configuration options](/core/configuration/complete)
---
# Themes
Pre-built themes for VistaView
Path: /styling/themes
import ThemePreviewButton from '../../../components/ThemePreviewButton.astro';
VistaView includes 17 pre-built themes that you can use out of the box. Each theme is a separate CSS file that can be imported alongside the base styles.
## Using Themes
```javascript
import 'vistaview/style.css'; // Base styles (required)
import 'vistaview/styles/dark-rounded.css'; // Theme (optional)
```
## Available Themes
### Dark Themes
#### dark-rounded
Modern dark theme with rounded corners and animated navigation buttons.
```javascript
import 'vistaview/styles/dark-rounded.css';
```
#### midnight-ocean
Deep navy blues with cyan accents.
```javascript
import 'vistaview/styles/midnight-ocean.css';
```
#### midnight-gold
Elegant black background with gold accents.
```javascript
import 'vistaview/styles/midnight-gold.css';
```
#### ember-glow
Dark theme with orange glow effects.
```javascript
import 'vistaview/styles/ember-glow.css';
```
#### neon-nights
Cyberpunk-inspired magenta and cyan with glowing effects.
```javascript
import 'vistaview/styles/neon-nights.css';
```
### Light Themes
#### paper-light
Light theme with subtle shadows and paper-like appearance.
```javascript
import 'vistaview/styles/paper-light.css';
```
#### ice-crystal
Cool light blue palette with crisp styling.
```javascript
import 'vistaview/styles/ice-crystal.css';
```
### Color Themes
#### autumn-amber
Warm oranges and browns with earthy tones.
```javascript
import 'vistaview/styles/autumn-amber.css';
```
#### cotton-candy
Playful pastel pink with soft styling.
```javascript
import 'vistaview/styles/cotton-candy.css';
```
#### forest-moss
Earthy greens inspired by nature.
```javascript
import 'vistaview/styles/forest-moss.css';
```
#### green-lake
Calming teal and green palette with smooth transitions.
```javascript
import 'vistaview/styles/green-lake.css';
```
#### lavender-fields
Soft purple palette with gentle animations.
```javascript
import 'vistaview/styles/lavender-fields.css';
```
#### mint-chocolate
Brown and mint green combination.
```javascript
import 'vistaview/styles/mint-chocolate.css';
```
#### soft-neutral
Warm beige and cream tones with maximum roundness.
```javascript
import 'vistaview/styles/soft-neutral.css';
```
#### strawberry
Vibrant pink and red gradient theme.
```javascript
import 'vistaview/styles/strawberry.css';
```
### Special Themes
#### stark-minimal
Pure black and white, zero border radius, minimalist design.
```javascript
import 'vistaview/styles/stark-minimal.css';
```
#### retro-arcade
Bold primary colors with classic arcade aesthetics.
```javascript
import 'vistaview/styles/retro-arcade.css';
```
## Theme Sizes
All themes are lightweight:
- **Smallest:** dark-rounded (0.69 KB, 0.26 KB gzip)
- **Largest:** retro-arcade (1.14 KB, 0.38 KB gzip)
- **Average:** ~0.83 KB (~0.30 KB gzip)
## Creating Custom Themes
See the [Custom Styling](/styling/custom) guide to create your own theme based on these examples.
## Next Steps
- Learn about [CSS variables](/styling/css-variables)
- Create [custom styling](/styling/custom)
- Explore [configuration options](/core/configuration/complete)
---
## API Reference
---
# Extensions
Extension system types and interfaces
Path: /api-reference/extensions
Extensions allow you to add custom functionality, content types, and UI controls to VistaView.
**Extension Types:** See [Types](/api-reference/types) for:
- [VistaExtension](/api-reference/types#vistaextension) - Extension interface
- [VistaDefaultCtrl](/api-reference/types#vistadefaultctrl) - Built-in control names
- [VistaImageParams](/api-reference/types#vistaimageparams) - Parameters for `onInitializeImage`
## Creating Extensions
Extensions implement the [VistaExtension](/api-reference/types#vistaextension) interface with optional hooks:
- `name` (required) - Unique identifier
- `description` (optional) - Human-readable description
- `control()` (optional) - Returns custom UI control element
- `onInitializeImage()` (optional) - Replace default image creation
- `onImageView()` (optional) - Triggered on navigation
- `onContentChange()` (optional) - Triggered on content/zoom changes
- `onDeactivateUi()` / `onReactivateUi()` (optional) - UI control state
- `onOpen()` / `onClose()` (optional) - Lightbox lifecycle
## Extension Example
Simple logger extension:
```typescript
import type { VistaExtension, VistaData } from 'vistaview';
import type { VistaView } from 'vistaview';
export function logger(): VistaExtension {
return {
name: 'logger',
description: 'Logs all lightbox events',
onOpen: (vistaView) => {
console.log('[Logger] Opened');
},
onClose: (vistaView) => {
console.log('[Logger] Closed');
},
onImageView: (data, vistaView) => {
console.log('[Logger] Image view:', data.index.to);
},
onContentChange: (content, vistaView) => {
console.log('[Logger] Content changed, scale:', content.scale);
},
};
}
// Usage
vistaView({
elements: '#gallery > a',
extensions: [logger()],
});
```
## Control Configuration
**Example:**
```typescript
vistaView({
elements: '#gallery > a',
controls: {
topRight: ['close'],
bottomCenter: ['indexDisplay'],
bottomRight: ['zoomIn', 'zoomOut'],
},
});
```
See [VistaDefaultCtrl](/api-reference/types#vistadefaultctrl) for built-in control names.
## Advanced Classes
These classes are exported for advanced use cases:
### VistaBox
Base class for content containers. Extend this to create custom content types.
```typescript
import { VistaBox } from 'vistaview';
import type { VistaImageParams } from 'vistaview';
export class CustomContentBox extends VistaBox {
element: HTMLDivElement;
constructor(params: VistaImageParams) {
super(params);
// Create custom element
this.element = document.createElement('div');
this.element.innerHTML = '
Custom content
';
// Setup required
this.element.classList.add('vvw-img-hi');
this.fullW = 800;
this.fullH = 600;
this.minW = 400;
this.maxW = 800;
this.element.style.width = `${this.fullW}px`;
this.element.style.height = `${this.fullH}px`;
this.setSizes({ stableSize: false, initDimension: true });
this.isLoadedResolved!(true);
}
}
```
### Other Classes
- [**VistaView**](/api-reference/classes/vistaview) - Main view controller class (available in all callbacks)
- [**VistaState**](/api-reference/classes/vistastate) - State management (accessible via `vistaView.state`)
- [**VistaBox**](/api-reference/classes/vistabox) - Base class for content containers
- [**VistaImage**](/api-reference/classes/vistaimage) - Individual image instance (extends VistaBox)
- [**VistaPointers**](/api-reference/classes/vistapointers) - Multi-pointer tracking system (see [VistaPointer](/api-reference/types#vistapointer))
- [**VistaImageEvent**](/api-reference/classes/vistaimageevent) - Event handling system
- [**VistaHiresTransition**](/api-reference/classes/vistahirestransition) - High-resolution image transition manager
## Utility Functions
### parseElement
Parses a DOM element or image config into parsed element data.
```typescript
import { parseElement } from 'vistaview/lib/utils';
const parsed = parseElement(element, index);
```
## Complete Extension Example
Custom download button extension:
```typescript
import type { VistaExtension, VistaData } from 'vistaview';
import type { VistaView } from 'vistaview';
export function downloadButton(): VistaExtension {
let downloadBtn: HTMLButtonElement | null = null;
return {
name: 'downloadButton',
description: 'Adds a download button',
control: () => {
downloadBtn = document.createElement('button');
downloadBtn.innerHTML = '⬇️ Download';
downloadBtn.className = 'vvw-download-btn';
downloadBtn.style.cssText = `
padding: 8px 16px;
background: rgba(0, 0, 0, 0.7);
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
`;
downloadBtn.addEventListener('click', (e) => {
e.stopPropagation();
// Download logic here
});
return downloadBtn;
},
onImageView: (data, vistaView) => {
if (downloadBtn) {
const mainImage = data.images.to![Math.floor(data.images.to!.length / 2)];
const src = mainImage.origin?.elm.querySelector('img')?.src || '';
// Update download URL
downloadBtn.onclick = (e) => {
e.stopPropagation();
const link = document.createElement('a');
link.href = src;
link.download = `image-${data.index.to! + 1}.jpg`;
link.click();
};
}
},
};
}
// Usage
vistaView({
elements: '#gallery > a',
extensions: [downloadButton()],
controls: {
bottomRight: ['downloadButton'],
},
});
```
## Related
- [Main Function](/api-reference/main-function)
- [Event Callbacks](/api-reference/events)
- [Types](/api-reference/types)
- [Extensions Authoring Guide](/extensions/authoring)
- [Built-in Extensions](/extensions/overview)
---
# Event Callbacks
Event callback functions and data types
Path: /api-reference/events
Event callbacks allow you to hook into different stages of the lightbox lifecycle.
## Event Callback Types
### onOpen
Triggered when the lightbox opens.
```typescript
onOpen?: (vistaView: VistaView) => void;
```
**Parameters:**
- `vistaView:` [VistaView](/api-reference/classes/vistaview) - The VistaView instance
**Example:**
```typescript
vistaView({
elements: '#gallery > a',
onOpen: (vistaView) => {
console.log('Lightbox opened');
console.log('Total images:', vistaView.state.elmLength);
},
});
```
### onClose
Triggered when the lightbox closes.
```typescript
onClose?: (vistaView: VistaView) => void;
```
**Parameters:**
- `vistaView:` [VistaView](/api-reference/classes/vistaview) - The VistaView instance
**Example:**
```typescript
vistaView({
elements: '#gallery > a',
onClose: (vistaView) => {
console.log('Lightbox closed');
console.log('Last viewed index:', vistaView.state.currentIndex);
},
});
```
### onImageView
Triggered when navigating between images or when opening at a specific image.
```typescript
onImageView?: (data: VistaData, vistaView: VistaView) => void;
```
**Parameters:**
- `data:` [VistaData](/api-reference/types#vistadata) - Navigation data with from/to information
- `vistaView:` [VistaView](/api-reference/classes/vistaview) - The VistaView instance
**Example:**
```typescript
vistaView({
elements: '#gallery > a',
onImageView: (data, vistaView) => {
console.log(`Viewing image ${data.index.to! + 1} of ${vistaView.state.elmLength}`);
if (data.via.next) console.log('→ Next');
if (data.via.prev) console.log('← Previous');
},
});
```
### onContentChange
Triggered when content changes (including zoom operations).
```typescript
onContentChange?: (content: VistaImageClone, vistaView: VistaView) => void;
```
**Parameters:**
- `content:` [VistaImageClone](/api-reference/types#vistaimageclone) - The changed content
- `vistaView:` [VistaView](/api-reference/classes/vistaview) - The VistaView instance
**Example:**
```typescript
vistaView({
elements: '#gallery > a',
onContentChange: (content, vistaView) => {
console.log('Zoom level:', content.state.transform.scale.toFixed(2) + 'x');
},
});
```
**Event Data Types:** See [Types](/api-reference/types) for:
- [VistaData](/api-reference/types#vistadata) - Navigation and transition data
- [VistaImageClone](/api-reference/types#vistaimageclone) - Current image state
- [VistaParsedElm](/api-reference/types#vistaparsedelm) - Parsed element information
- [VistaImgOrigin](/api-reference/types#vistaimgorigin) - Origin element properties
## Related
- [Main Function](/api-reference/main-function)
- [Lifecycle Functions](/api-reference/lifecycle)
- [Types](/api-reference/types)
- [Events Configuration Guide](/core/configuration/events)
---
# Lifecycle Functions
Custom lifecycle functions for overriding default behavior
Path: /api-reference/lifecycle
Lifecycle functions allow you to override VistaView's default behavior at key stages.
**Lifecycle Function Types:** See [Types](/api-reference/types) for:
- [VistaInitFn](/api-reference/types#vistainitfn) - Custom initialization function
- [VistaImageSetupFn](/api-reference/types#vistaimagesetupfn) - Custom setup function
- [VistaTransitionFn](/api-reference/types#vistatransitionfn) - Custom transition function
- [VistaOpenFn](/api-reference/types#vistaopenfn) - Custom open function
- [VistaCloseFn](/api-reference/types#vistaclosefn) - Custom close function
## Usage Examples
### Custom Initialization
```typescript
import { vistaView, init } from 'vistaview';
vistaView({
elements: '#gallery > a',
initFunction: (vistaView) => {
// Call default initialization
init(vistaView);
// Add custom initialization
console.log('Custom initialization');
console.log('Total images:', vistaView.state.elmLength);
},
});
```
### Custom Image Setup
```typescript
import { vistaView, imageSetup } from 'vistaview';
vistaView({
elements: '#gallery > a',
imageSetupFunction: (data, vistaView) => {
// Call default setup
imageSetup(data, vistaView);
// Custom setup logic
console.log('Setting up image:', data.index.to);
},
});
```
### Custom Transition
```typescript
import { vistaView, transition } from 'vistaview';
vistaView({
elements: '#gallery > a',
transitionFunction: (data, abortSignal, vistaView) => {
// Use default transition
return transition(data, abortSignal, vistaView);
},
});
```
**Custom fade transition:**
```typescript
vistaView({
elements: '#gallery > a',
transitionFunction: (data, abortSignal, vistaView) => {
const elements = data.htmlElements;
if (elements.from && elements.to) {
const fromElms = elements.from;
const toElms = elements.to;
// Fade out old images
fromElms.forEach((elm) => {
elm.style.transition = 'opacity 300ms ease';
elm.style.opacity = '0';
});
// Fade in new images
toElms.forEach((elm) => {
elm.style.opacity = '0';
elm.style.transition = 'opacity 300ms ease';
setTimeout(() => (elm.style.opacity = '1'), 50);
});
const transitionEnded = new Promise((resolve) => {
setTimeout(resolve, 350);
});
return {
cleanup: () => {},
transitionEnded,
};
}
},
});
```
### Custom Close
```typescript
import { vistaView, close } from 'vistaview';
vistaView({
elements: '#gallery > a',
closeFunction: (vistaView) => {
console.log('Custom close logic');
// Call default close
close(vistaView);
},
});
```
## Default Behavior Functions
These functions implement the default behavior and can be imported for use in custom function overrides:
### init
Default initialization function.
```typescript
import { init } from 'vistaview';
vistaView({
elements: '#gallery > a',
initFunction: (vistaView) => {
init(vistaView);
// Add custom logic after default init
},
});
```
### open
Default open function.
```typescript
import { open } from 'vistaview';
```
### close
Default close function.
```typescript
import { close } from 'vistaview';
vistaView({
elements: '#gallery > a',
closeFunction: (vistaView) => {
// Custom logic before close
console.log('Closing lightbox');
// Call default close
close(vistaView);
},
});
```
### transition
Default transition animation function.
```typescript
import { transition } from 'vistaview';
vistaView({
elements: '#gallery > a',
transitionFunction: (data, abortSignal, vistaView) => {
return transition(data, abortSignal, vistaView);
},
});
```
### imageSetup
Default image setup function.
```typescript
import { imageSetup } from 'vistaview';
vistaView({
elements: '#gallery > a',
imageSetupFunction: (data, vistaView) => {
imageSetup(data, vistaView);
// Add custom setup logic
},
});
```
### DefaultOptions
Default configuration options object. See [VistaOpt](/api-reference/types#vistaopt) for all configuration options.
```typescript
import { DefaultOptions } from 'vistaview';
const DefaultOptions: VistaOpt = {
animationDurationBase: 333,
maxZoomLevel: 2,
preloads: 1,
keyboardListeners: true,
arrowOnSmallScreens: false,
rapidLimit: 222,
controls: {
topLeft: ['indexDisplay'],
topRight: ['zoomIn', 'zoomOut', 'close'],
bottomLeft: ['description'],
},
};
```
## Related
- [Main Function](/api-reference/main-function)
- [Event Callbacks](/api-reference/events)
- [Types](/api-reference/types)
- [Lifecycle Configuration Guide](/core/configuration/lifecycle)
---
# Types
TypeScript type definitions and interfaces
Path: /api-reference/types
Complete TypeScript type definitions for VistaView.
## Core Types
### VistaParams
Main configuration interface including the `elements` property.
```typescript
interface VistaParams extends VistaOpt {
elements: string | VistaImgConfig[];
}
```
**Properties:**
- `elements` (required): CSS selector string or array of [VistaImgConfig](#vistaimgconfig) configurations
- Extends [VistaOpt](#vistaopt) with all configuration options
### VistaOpt
Base configuration options interface.
```typescript
interface VistaOpt {
// Animation
animationDurationBase?: number;
// Zoom
maxZoomLevel?: number;
// Preloading
preloads?: number;
// Interaction
keyboardListeners?: boolean;
arrowOnSmallScreens?: boolean;
rapidLimit?: number;
// Styling
initialZIndex?: number;
// Controls
controls?: {
topLeft?: (VistaDefaultCtrl | string)[];
topRight?: (VistaDefaultCtrl | string)[];
topCenter?: (VistaDefaultCtrl | string)[];
bottomCenter?: (VistaDefaultCtrl | string)[];
bottomLeft?: (VistaDefaultCtrl | string)[];
bottomRight?: (VistaDefaultCtrl | string)[];
};
// Extensions
extensions?: VistaExtension[];
// Event Callbacks
onOpen?: (vistaView: VistaView) => void;
onClose?: (vistaView: VistaView) => void;
onImageView?: (data: VistaData, vistaView: VistaView) => void;
onContentChange?: (content: VistaImageClone, vistaView: VistaView) => void;
// Lifecycle Functions
initFunction?: VistaInitFn;
imageSetupFunction?: VistaImageSetupFn;
transitionFunction?: VistaTransitionFn;
openFunction?: VistaOpenFn;
closeFunction?: VistaCloseFn;
}
```
**Related Types:**
- [VistaDefaultCtrl](#vistadefaultctrl) - Control names
- [VistaExtension](#vistaextension) - Extension system
- [VistaData](#vistadata), [VistaImageClone](#vistaimageclone) - Event data
- [VistaInitFn](#vistainitfn), [VistaImageSetupFn](#vistaimagesetupfn), [VistaTransitionFn](#vistatransitionfn), [VistaOpenFn](#vistaopenfn), [VistaCloseFn](#vistaclosefn) - Lifecycle functions
### VistaInterface
Instance interface with control methods returned by `vistaView()`.
```typescript
interface VistaInterface {
open(index?: number): void;
close(): Promise;
view(index: number): void;
next(): void;
prev(): void;
reset(): void;
zoomIn(): void;
zoomOut(): void;
getCurrentIndex(): number;
destroy(): void;
}
```
**Methods:**
- `open(index?)` - Opens lightbox at specified index
- `close()` - Closes lightbox (returns Promise)
- `view(index)` - Navigate to specific image
- `next()` - Navigate to next image
- `prev()` - Navigate to previous image
- `reset()` - Recalculate elements and re-attach event listeners (useful after DOM changes)
- `zoomIn()` - Zoom in
- `zoomOut()` - Zoom out
- `getCurrentIndex()` - Get current image index
- `destroy()` - Destroy instance and cleanup
### VistaImgConfig
Image configuration object.
```typescript
interface VistaImgConfig {
src: string;
alt?: string;
srcSet?: string;
}
```
**Properties:**
- `src` (required): Image URL
- `alt` (optional): Alt text for accessibility
- `srcSet` (optional): Responsive image sources
## Event Data Types
### VistaData
Data passed to event callbacks and transition functions.
```typescript
interface VistaData {
htmlElements: {
from: HTMLElement[] | null;
to: HTMLElement[] | null;
};
images: {
from: VistaBox[] | null;
to: VistaBox[] | null;
};
index: {
from: number | null;
to: number | null;
};
via: {
next: boolean;
prev: boolean;
};
}
```
**Properties:**
- `htmlElements.from` - Previous HTML elements
- `htmlElements.to` - New HTML elements
- `images.from` - Previous image objects
- `images.to` - New image objects
- `index.from` - Previous image index (null on initial open)
- `index.to` - New image index
- `via.next` - True if navigated via next
- `via.prev` - True if navigated via previous
### VistaImageClone
Current image state passed to `onContentChange` callback.
```typescript
interface VistaImageClone {
config: {
src: string;
alt?: string;
srcSet?: string;
};
origin: {
src: string;
srcSet: string;
borderRadius: string;
objectFit: string;
} | null;
parsedSrcSet?: { src: string; width: number }[];
element: string;
thumb?: string;
index: number;
pos: number;
state: {
width: number;
height: number;
transform: {
x: number;
y: number;
scale: number;
};
translate: {
x: number;
y: number;
};
};
}
```
**Properties:**
- `config` - Image configuration (src, alt, srcSet)
- `origin` - Original element properties (null for non-image content)
- `parsedSrcSet` - Parsed srcSet attribute
- `element` - HTML string of the content
- `thumb` - Thumbnail URL (if applicable)
- `index` - Current image index
- `pos` - Position in the view
- `state.width` - Current width
- `state.height` - Current height
- `state.transform` - Transform state (x, y, scale)
- `state.translate` - Translation offsets (x, y)
### VistaParsedElm
Parsed element information passed to extensions.
```typescript
interface VistaParsedElm {
config: VistaImgConfig;
parsedSrcSet?: { src: string; width: number }[];
origin?: VistaImgOrigin;
}
```
**Properties:**
- `config` - Image configuration ([VistaImgConfig](#vistaimgconfig))
- `parsedSrcSet` - Parsed srcSet attribute with sources and widths
- `origin` - Origin element properties ([VistaImgOrigin](#vistaimgorigin))
### VistaImgOrigin
Origin element properties for animations.
```typescript
interface VistaImgOrigin {
anchor?: HTMLAnchorElement;
image: HTMLImageElement;
src: string;
srcSet: string;
borderRadius: string;
objectFit: string;
}
```
**Properties:**
- `anchor` - The original anchor element (if exists)
- `image` - The original image element
- `src` - Original image source
- `srcSet` - Original srcSet attribute
- `borderRadius` - Original border radius style
- `objectFit` - Original object-fit style
## Lifecycle Function Types
### VistaInitFn
Type for custom initialization function.
```typescript
type VistaInitFn = (vistaView: VistaView) => void;
```
**Parameters:**
- `vistaView:` [VistaView](/api-reference/classes/vistaview) - The VistaView instance
### VistaImageSetupFn
Type for custom setup function when navigating between images.
```typescript
type VistaImageSetupFn = (data: VistaData, vistaView: VistaView) => void;
```
**Parameters:**
- `data:` [VistaData](#vistadata) - Navigation data
- `vistaView:` [VistaView](/api-reference/classes/vistaview) - The VistaView instance
### VistaTransitionFn
Type for custom transition animation function.
```typescript
type VistaTransitionFn = (
data: VistaData,
abortSignal: AbortSignal,
vistaView: VistaView
) => { cleanup: () => void; transitionEnded: Promise } | void;
```
**Parameters:**
- `data:` [VistaData](#vistadata) - Navigation data
- `abortSignal: AbortSignal` - Signal to abort the transition
- `vistaView:` [VistaView](/api-reference/classes/vistaview) - The VistaView instance
**Returns:** Object with cleanup function and promise, or void
### VistaOpenFn
Type for custom open function.
```typescript
type VistaOpenFn = (vistaView: VistaView) => void;
```
**Parameters:**
- `vistaView:` [VistaView](/api-reference/classes/vistaview) - The VistaView instance
### VistaCloseFn
Type for custom close function.
```typescript
type VistaCloseFn = (vistaView: VistaView) => void;
```
**Parameters:**
- `vistaView:` [VistaView](/api-reference/classes/vistaview) - The VistaView instance
## Extension Types
### VistaExtension
Interface for creating extensions.
```typescript
interface VistaExtension {
name: string;
description?: string;
control?: () => HTMLElement | null;
onInitializeImage?: (parsed: VistaImageParams) => VistaBox | void | null | undefined;
onImageView?: (data: VistaData, vistaView: VistaView) => void;
onContentChange?: (content: VistaImageClone, vistaView: VistaView) => void;
onDeactivateUi?: (names: string[], requestBy: VistaBox | null, vistaView: VistaView) => void;
onReactivateUi?: (names: string[], requestBy: VistaBox | null, vistaView: VistaView) => void;
onOpen?: (vistaView: VistaView) => void;
onClose?: (vistaView: VistaView) => void;
}
```
**Properties:**
- `name` (required) - Unique identifier for the extension
- `description` (optional) - Human-readable description
- `control` (optional) - Returns a custom UI control element
- `onInitializeImage` (optional) - Hook to replace default image creation
- `onImageView` (optional) - Triggered when navigating between images
- `onContentChange` (optional) - Triggered when content changes
- `onDeactivateUi` (optional) - Triggered when UI controls are deactivated
- `onReactivateUi` (optional) - Triggered when UI controls are reactivated
- `onOpen` (optional) - Triggered when lightbox opens
- `onClose` (optional) - Triggered when lightbox closes
**Type References:**
- [VistaImageParams](#vistaimageparams) - Used in `onInitializeImage`
- [VistaData](#vistadata) - Used in `onImageView`
- [VistaImageClone](#vistaimageclone) - Used in `onContentChange`
## Control Types
### VistaDefaultCtrl
Built-in control names.
```typescript
type VistaDefaultCtrl = 'indexDisplay' | 'zoomIn' | 'zoomOut' | 'close' | 'description';
```
## Advanced Types
### VistaImageParams
Parameters passed to extension `onInitializeImage` hook.
```typescript
interface VistaImageParams {
elm: VistaParsedElm;
pos: number;
index: number;
maxZoomLevel: number;
onScale: (par: { vistaImage: VistaBox; scale: number; isMax: boolean; isMin: boolean }) => void;
vistaView: VistaView;
transitionState?: VistaHiresTransitionOpt;
transitionShouldWait?: () => boolean;
}
```
**Properties:**
- `elm` - Parsed element ([VistaParsedElm](#vistaparsedelm))
- `pos` - Position in the view
- `index` - Image index
- `maxZoomLevel` - Maximum zoom level
- `onScale` - Callback for scale changes
- `vistaView` - [VistaView](/api-reference/classes/vistaview) instance
- `transitionState` - Optional transition state
- `transitionShouldWait` - Optional transition wait function
## Pointer Event Types
### VistaPointer
Represents a single pointer (mouse, touch, or pen) position and movement.
```typescript
type VistaPointer = {
x: number;
y: number;
movementX: number;
movementY: number;
id: number | string;
};
```
**Properties:**
- `x` - Current X coordinate
- `y` - Current Y coordinate
- `movementX` - Movement delta on X axis since last event
- `movementY` - Movement delta on Y axis since last event
- `id` - Unique identifier for this pointer
### VistaPointerListenerArgs
Arguments passed to internal pointer listeners used by `VistaPointers`.
```typescript
type VistaPointerListenerArgs = {
event: 'down' | 'move' | 'up' | 'cancel';
pointer: VistaPointer;
pointers: VistaPointer[];
lastPointerLen: number;
};
```
**Properties:**
- `event` - Type of pointer event
- `pointer` - Current [VistaPointer](#vistapointer) data
- `pointers` - Array of all active [VistaPointer](#vistapointer) instances
- `lastPointerLen` - Previous number of active pointers (for detecting pointer count changes)
### VistaPointerListener
A listener function passed to `VistaPointers` via `VistaPointerArgs.listeners` or `addEventListener()`.
```typescript
type VistaPointerListener = (args: VistaPointerListenerArgs) => void;
```
**Parameters:**
- `args` - [VistaPointerListenerArgs](#vistapointerlistenerargs) event data
### VistaExternalPointerListenerArgs
Arguments passed to external pointer listeners registered via [`registerPointerListener()`](/api-reference/classes/vistaview#registerpointerlistener).
```typescript
type VistaExternalPointerListenerArgs = {
event: 'down' | 'move' | 'up' | 'cancel';
pointer: VistaPointer;
pointers: VistaPointer[];
lastPointerLen: number;
state: VistaState;
hasInternalExecution: boolean;
abortController: AbortController | null;
};
```
**Properties:**
- `event` - Type of pointer event
- `pointer` - Current [VistaPointer](#vistapointer) data
- `pointers` - Array of all active [VistaPointer](#vistapointer) instances
- `lastPointerLen` - Previous number of pointers (for detecting changes)
- `state` - [VistaState](/api-reference/classes/vistastate) instance
- `hasInternalExecution` - Whether VistaView handled this event internally
- `abortController` - Controller for canceling operations
## Related
- [Main Function](/api-reference/main-function)
- [Event Callbacks](/api-reference/events)
- [Lifecycle Functions](/api-reference/lifecycle)
- [Extensions](/api-reference/extensions)
---
# Main Function
vistaView() function, configuration, and instance methods
Path: /api-reference/main-function
## vistaView()
Creates and initializes a lightbox instance. This function is the primary entry point that instantiates the [VistaView](/api-reference/classes/vistaview) class.
```typescript
function vistaView(params: VistaParams): VistaInterface | null;
```
**Parameters:**
- `params:` [VistaParams](/api-reference/types#vistaparams) - Configuration object
**Returns:** [VistaInterface](/api-reference/types#vistainterface) or `null` if no valid elements are found or input is invalid
**Example:**
```typescript
import { vistaView } from 'vistaview';
import 'vistaview/style.css';
const gallery = vistaView({
elements: '#gallery > a',
maxZoomLevel: 3,
preloads: 2,
});
```
:::note
The `vistaView()` function (lowercase 'v') is the factory function, while [VistaView](/api-reference/classes/vistaview) (capital 'V') is the underlying class. For most use cases, use the `vistaView()` function. Direct access to the VistaView class is useful for TypeScript type imports and advanced extensions.
:::
**Configuration:** See [Types](/api-reference/types) for:
- [VistaParams](/api-reference/types#vistaparams) - Main configuration interface
- [VistaOpt](/api-reference/types#vistaopt) - All configuration options
- [VistaImgConfig](/api-reference/types#vistaimgconfig) - Image configuration object
## Instance Methods
The `vistaView()` function returns a [VistaInterface](/api-reference/types#vistainterface) object with the following methods:
### open(index?)
Opens the lightbox at the specified index (0-based).
```typescript
open(index?: number): void;
```
**Parameters:**
- `index` (optional): Image index to open at (default: 0)
**Example:**
```typescript
const gallery = vistaView({ elements: '#gallery > a' });
gallery.open(); // Open at first image
gallery.open(0); // Open at first image
gallery.open(2); // Open at third image
```
### close()
Closes the lightbox.
```typescript
close(): Promise;
```
**Returns:** Promise that resolves when close animation completes
**Example:**
```typescript
await gallery.close();
console.log('Gallery closed');
```
### view(index)
Navigates to a specific image while the lightbox is open.
```typescript
view(index: number): void;
```
**Parameters:**
- `index` (required): Image index to navigate to (0-based)
**Example:**
```typescript
gallery.view(2); // Go to third image
```
### next()
Navigates to the next image. Wraps to first image when at the end.
```typescript
next(): void;
```
**Example:**
```typescript
gallery.next();
```
### prev()
Navigates to the previous image. Wraps to last image when at the beginning.
```typescript
prev(): void;
```
**Example:**
```typescript
gallery.prev();
```
### reset()
Recalculates elements and re-attaches event listeners. Useful after DOM changes.
```typescript
reset(): void;
```
**Example:**
```typescript
// After adding new images to the DOM
document.querySelector('#gallery')!.innerHTML += `
`;
// Refresh the gallery
gallery.reset();
```
### zoomIn()
Zooms in on the current image.
```typescript
zoomIn(): void;
```
**Example:**
```typescript
gallery.zoomIn();
```
### zoomOut()
Zooms out on the current image.
```typescript
zoomOut(): void;
```
**Example:**
```typescript
gallery.zoomOut();
```
### getCurrentIndex()
Returns the current image index (0-based).
```typescript
getCurrentIndex(): number;
```
**Returns:** Current image index
**Example:**
```typescript
const currentIndex = gallery.getCurrentIndex();
console.log(`Viewing image ${currentIndex + 1}`);
```
### destroy()
Destroys the lightbox instance and removes all event listeners.
```typescript
destroy(): void;
```
**Example:**
```typescript
gallery.destroy();
```
## Related
- [Event Callbacks](/api-reference/events)
- [Lifecycle Functions](/api-reference/lifecycle)
- [Complete Configuration Guide](/core/configuration/complete)
---
# VistaBox Class
Base class for image and custom content containers
Path: /api-reference/classes/vistabox
The `VistaBox` class is an abstract base class for all content types in VistaView. Extend this class to create custom content types like videos, maps, or interactive elements.
## Overview
`VistaBox` handles:
- Image sizing and scaling
- Zoom and pan transformations
- Lifecycle management (init, load, destroy)
- State management for width, height, and transformations
**Use Case:** Create custom content extensions by extending VistaBox. See [Extensions](/api-reference/extensions) for examples.
## Public Properties
### element
```typescript
abstract element: HTMLImageElement | HTMLDivElement
```
The DOM element containing the content. Must be implemented by subclasses.
### state
```typescript
state: VistaImageState;
```
Current state of the image including dimensions and transformations. Contains internal properties prefixed with `_` (e.g., `_width`, `_height`, `_transform`).
### pos
```typescript
pos: number;
```
Position relative to the current image (`0` = center, `-1` = left, `1` = right).
### index
```typescript
index: number;
```
Zero-based index in the gallery.
### config
```typescript
config: VistaImgConfig;
```
Image configuration containing `src`, `alt`, and `srcSet`.
### origin
```typescript
origin: VistaImgOrigin | undefined;
```
Information about the origin element (thumbnail) in the DOM.
### isReady
```typescript
isReady: boolean;
```
Whether the content has finished loading.
### thumb
```typescript
thumb: HTMLDivElement | null;
```
Thumbnail element used during transitions.
## Public Methods
### constructor()
```typescript
constructor(par: VistaImageParams)
```
Creates a new VistaBox instance. Called by [VistaView](/api-reference/classes/vistaview) during initialization.
### init()
```typescript
async init(): Promise
```
Initializes the content. Override this to implement custom loading logic.
### setSizes()
```typescript
setSizes(par?: { stableSize?: boolean; initDimension?: boolean }): void
```
Calculates and sets dimensions based on viewport and content size.
**Parameters:**
- `par.stableSize` - Use cached dimensions without recalculation
- `par.initDimension` - Calculate initial dimensions from origin element
### prepareClose()
```typescript
prepareClose(): void
```
Prepares the element for closing transition. Called before the lightbox closes.
### cancelPendingLoad()
```typescript
cancelPendingLoad(): void
```
Cancels any in-progress image loading operations.
### destroy()
```typescript
destroy(): void
```
Cleans up resources and removes event listeners. Called when the element is no longer needed.
### cloneStyleFrom()
```typescript
cloneStyleFrom(img: VistaBox, state?: VistaHiresTransitionOpt): void
```
Copies style and state from another VistaBox instance. Used during transitions to maintain visual continuity.
### toObject()
```typescript
toObject(): VistaImageClone
```
Returns a serializable representation of the current state. Used for the `onContentChange` event.
### setInitialCenter()
```typescript
setInitialCenter(center: { x: number; y: number }): void
```
Sets the center point for zoom and pan operations.
### onImageReady()
```typescript
onImageReady(): void
```
Override this method to perform actions when the content is ready.
### animateZoom()
```typescript
animateZoom(scaleFactor: number, center?: { x: number; y: number }): void
```
Override to implement custom zoom animation logic.
### scaleMove()
```typescript
scaleMove(scaleFactor: number, center?: { x: number; y: number }, animate?: boolean): void
```
Override to implement custom scale and movement logic.
### theThrow()
```typescript
theThrow(par: { x: number; y: number }): () => void
```
Override to implement momentum scrolling after a swipe gesture.
## Protected Properties
The following protected properties are available when extending VistaBox:
### initH
```typescript
protected initH: number = 0
```
Initial height of the content based on thumbnail dimensions.
### initW
```typescript
protected initW: number = 0
```
Initial width of the content based on thumbnail dimensions.
### fullH
```typescript
protected fullH: number = 0
```
Full height of the content when displayed in the lightbox.
### fullW
```typescript
protected fullW: number = 0
```
Full width of the content when displayed in the lightbox.
### maxW
```typescript
protected maxW: number = 0
```
Maximum allowed width for the content.
### minW
```typescript
protected minW: number = 0
```
Minimum allowed width for the content.
### defaultWH
```typescript
protected defaultWH: number = 200
```
Default width/height fallback value.
### isZoomedIn
```typescript
protected isZoomedIn: boolean = false
```
Whether the content is currently zoomed in.
### isCancelled
```typescript
protected isCancelled: boolean = false
```
Whether the loading operation has been cancelled.
### isLoadedResolved
```typescript
protected isLoadedResolved: ((val: boolean | PromiseLike) => void) | null = null
```
Resolver function for the `isLoaded` promise.
### isLoadedRejected
```typescript
protected isLoadedRejected: ((reason?: any) => void) | null = null
```
Rejection function for the `isLoaded` promise.
### isLoaded
```typescript
protected isLoaded: Promise
```
Promise that resolves when the content has finished loading.
### replacement
```typescript
protected replacement: HTMLImageElement | null = null
```
Placeholder element that replaces the original thumbnail in the DOM.
### originalParent
```typescript
protected originalParent: HTMLElement | null = null
```
Reference to the original parent element of the thumbnail.
### originalNextSibling
```typescript
protected originalNextSibling: ChildNode | null = null
```
Reference to the next sibling of the original thumbnail for proper reinsertion.
### originalStyle
```typescript
protected originalStyle = ''
```
Original CSS text of the thumbnail element.
### thumbImage
```typescript
protected thumbImage: HTMLImageElement | null = null
```
Reference to the original thumbnail image element.
### originRect
```typescript
protected originRect: { width: number; height: number; top: number; left: number }
```
Bounding rectangle of the origin element.
### fittedSize
```typescript
protected fittedSize: { width: number; height: number } | null = null
```
Calculated fitted size of the thumbnail image.
### maxZoomLevel
```typescript
protected maxZoomLevel: number
```
Maximum zoom level allowed for this content.
### vistaView
```typescript
protected vistaView: VistaView
```
Reference to the parent VistaView instance.
### transitionState
```typescript
protected transitionState: VistaHiresTransitionOpt | null = null
```
State object for high-resolution transitions.
### transitionShouldWait
```typescript
protected transitionShouldWait: () => boolean = () => false
```
Function that determines if transition should wait before starting.
### initPointerCenter
```typescript
protected initPointerCenter = { x: 0, y: 0 }
```
Initial center point for pointer interactions.
### onScale
```typescript
protected onScale: (par: {
vistaImage: VistaBox;
scale: number;
isMax: boolean;
isMin: boolean;
}) => void
```
Callback function invoked when content is scaled.
## Protected Methods
The following protected methods are available when extending VistaBox:
### createState()
```typescript
protected createState(): VistaImageState
```
Creates and returns a new state object with getters/setters that trigger DOM updates. Called in the constructor.
### onLessThanMinWidthChange()
```typescript
protected onLessThanMinWidthChange(value: boolean): void
```
Called when content width falls below minimum. Sets opacity to 0.5 when true.
### onTranslateChange()
```typescript
protected onTranslateChange(value: { x: number; y: number }): void
```
Updates the CSS translate property when state.translate changes.
### onTransformChange()
```typescript
protected onTransformChange(value: { x: number; y: number; scale: number }): void
```
Updates the CSS transform property when state.transform changes.
### onWidthChange()
```typescript
protected onWidthChange(value: number): void
```
Updates the CSS width property when state.width changes.
### onHeightChange()
```typescript
protected onHeightChange(value: number): void
```
Updates the CSS height property when state.height changes.
### getFullSizeDim()
```typescript
protected getFullSizeDim(): { width: number; height: number }
```
Calculates the full size dimensions based on thumbnail aspect ratio and viewport size.
**Returns:** Object containing calculated width and height.
### normalize()
```typescript
protected normalize(): void
```
Resets content to its default state with no zoom or translation. Sets transform and translate to zero, and dimensions to full size.
### getFromParsedSrcSet()
```typescript
protected getFromParsedSrcSet(targetWidth: number): string | null
```
Selects the most appropriate source from the parsed srcSet based on target width and device pixel ratio.
**Parameters:**
- `targetWidth` - The desired width in pixels
**Returns:** The selected source URL, or null if no srcSet is available.
### setFinalTransform()
```typescript
setFinalTransform(par?: { propagateEvent?: boolean }): { close: boolean; cancel: () => void }
```
Finalizes the current transform state by converting temporary transforms into permanent translate and size values. Called at the end of pan/zoom operations.
**Parameters:**
- `par.propagateEvent` - Whether to trigger onContentChange events (default: true)
**Returns:** Object with close flag and cancel function.
## Related
- [VistaImage](/api-reference/classes/vistaimage) - Image implementation extending VistaBox
- [Extensions](/api-reference/extensions) - Creating custom content types
- [VistaImageParams](/api-reference/types#vistaimageparams) - Constructor parameters
---
# VistaHiresTransition Class
High-resolution image transition manager
Path: /api-reference/classes/vistahirestransition
The `VistaHiresTransition` class manages smooth animated transitions when images are loaded or when dimensions/positions change.
## Overview
`VistaHiresTransition` provides:
- Smooth easing animations for size and position changes
- Concurrent animation management
- Frame-by-frame state interpolation
- Animation cancellation
**Use Case:** Used internally by [VistaImage](/api-reference/classes/vistaimage) to animate dimension and transform changes. Typically not used directly by applications.
## Public Properties
None - all properties and map are private/static.
## Public Static Methods
### start()
```typescript
static start(options: {
vistaImage: VistaBox;
onComplete: () => void;
shouldWait: () => boolean;
target: {
width?: number;
height?: number;
transform?: { x?: number; y?: number; scale?: number };
translate?: { x?: number; y?: number };
};
}): void
```
Starts an animated transition for a VistaBox instance.
**Parameters:**
- `vistaImage` - The [VistaBox](/api-reference/classes/vistabox) instance to animate
- `onComplete` - Callback when animation completes
- `shouldWait` - Function returning `true` to pause animation
- `target` - Target dimensions and transformations to animate to
**Example:**
```typescript
import { VistaHiresTransition } from 'vistaview';
VistaHiresTransition.start({
vistaImage: image,
onComplete: () => console.log('Animation complete'),
shouldWait: () => false,
target: {
width: 800,
height: 600,
transform: { scale: 1.5, x: 0, y: 0 },
},
});
```
### stop()
```typescript
static stop(vistaImage: VistaBox): VistaHiresTransitionOpt | undefined
```
Stops an active animation for a VistaBox instance.
**Parameters:**
- `vistaImage` - The [VistaBox](/api-reference/classes/vistabox) instance
**Returns:** The animation state at the time of stopping, or `undefined` if no animation was running
**Example:**
```typescript
const state = VistaHiresTransition.stop(image);
if (state) {
console.log('Stopped at:', state.current);
}
```
## Animation Behavior
- Uses **easing function** (20% of remaining distance per frame) for smooth motion
- Stops when values are within threshold (1px for position, 0.005 for scale)
- Handles multiple concurrent animations per instance
- Respects `shouldWait` callback to pause during rapid navigation
## Related
- [VistaBox](/api-reference/classes/vistabox) - Container class that uses transitions
- [VistaImage](/api-reference/classes/vistaimage) - Image class that triggers transitions
- [VistaView](/api-reference/classes/vistaview) - Main controller
---
# VistaImage Class
Image implementation extending VistaBox
Path: /api-reference/classes/vistaimage
The `VistaImage` class extends [VistaBox](/api-reference/classes/vistabox) and implements image-specific functionality including responsive images, hi-res loading, and zoom/pan controls.
## Overview
`VistaImage` is the default content type used by VistaView for displaying images. It automatically handles:
- Progressive image loading with thumbnails
- Responsive images with `srcset` support
- Zoom and pan interactions
- Hi-resolution image transitions
## Usage
Typically, you don't instantiate `VistaImage` directly - [VistaView](/api-reference/classes/vistaview) creates instances automatically. However, you can reference it when creating custom extensions.
```typescript
import { VistaImage } from 'vistaview';
// Used internally by VistaView
const image = new VistaImage(params);
```
## Public Properties
Inherits all properties from [VistaBox](/api-reference/classes/vistabox):
- `element` - HTMLImageElement containing the image
- `state` - Current dimensions and transformations
- `pos` - Position relative to current image
- `index` - Gallery index
- `config` - Image configuration
- `origin` - Origin element information
- `isReady` - Whether image has loaded
- `thumb` - Thumbnail element
## Public Methods
### constructor()
```typescript
constructor(par: VistaImageParams)
```
Creates a new VistaImage instance with automatic image loading.
### Inherited Methods
All public methods from [VistaBox](/api-reference/classes/vistabox) are available:
- `init()` - Initialize the image
- `setSizes()` - Calculate dimensions
- `prepareClose()` - Prepare for closing
- `cancelPendingLoad()` - Cancel loading
- `destroy()` - Clean up resources
- `cloneStyleFrom()` - Copy style from another instance
- `toObject()` - Serialize current state
- `setInitialCenter()` - Set zoom center point
## Related
- [VistaBox](/api-reference/classes/vistabox) - Base class
- [VistaView](/api-reference/classes/vistaview) - Main controller
- [Extensions](/api-reference/extensions) - Creating custom content types
---
# VistaImageEvent Class
Event handling system for pointer interactions
Path: /api-reference/classes/vistaimageevent
The `VistaImageEvent` class manages pointer events and translates them into image manipulation actions like zooming, panning, and navigation.
## Overview
`VistaImageEvent` coordinates:
- Single and multi-touch gestures
- Pinch-to-zoom detection
- Pan/drag interactions when zoomed
- Momentum scrolling
- External pointer event listeners
**Use Case:** Created internally by [VistaView](/api-reference/classes/vistaview). Extensions can register listeners through [`registerPointerListener()`](/api-reference/classes/vistaview#registerpointerlistener).
## Public Properties
None - all properties are private.
## Public Methods
### constructor()
```typescript
constructor(vvw: VistaView)
```
Creates a new event handling system for a [VistaView](/api-reference/classes/vistaview) instance.
### registerPointerListener()
```typescript
registerPointerListener(listener: (e: VistaExternalPointerListenerArgs) => void): void
```
Registers an external pointer event listener. Same as calling [`viewer.registerPointerListener()`](/api-reference/classes/vistaview#registerpointerlistener).
**Parameters:**
- `listener` - Function receiving [pointer event data](/api-reference/types#vistaexternalpointerlistenerargs)
**Example:**
```typescript
const eventSystem = new VistaImageEvent(viewer);
eventSystem.registerPointerListener((e) => {
console.log('Event:', e.event);
console.log('Pointers:', e.pointers.length);
console.log('State:', e.state.zoomedIn);
});
```
### start()
```typescript
start(imageContainer: HTMLElement): void
```
Starts listening to pointer events on the specified container. Called automatically by [VistaView](/api-reference/classes/vistaview) when opening.
**Parameters:**
- `imageContainer` - The element to attach event listeners to
### stop()
```typescript
stop(): void
```
Removes all event listeners and cleans up resources. Called automatically by [VistaView](/api-reference/classes/vistaview) when closing.
## Related
- [VistaView](/api-reference/classes/vistaview) - Main controller that uses VistaImageEvent
- [VistaPointers](/api-reference/classes/vistapointers) - Underlying pointer tracking system
- [VistaExternalPointerListenerArgs](/api-reference/types#vistaexternalpointerlistenerargs) - Event data type
---
# VistaView Class
The core VistaView class - the main controller for the lightbox viewer
Path: /api-reference/classes/vistaview
The `VistaView` class is the core controller that manages the entire lifecycle of the lightbox viewer. Each instance represents a lightbox that can be opened, navigated, and controlled programmatically.
## Overview
`VistaView` orchestrates all aspects of the lightbox experience:
- **Instance Management**: Ensures only one lightbox is active at a time via `GlobalVistaState`
- **Image Navigation**: Handles next/prev navigation with smooth transitions and rapid-swap optimization
- **UI Controls**: Manages zoom, close, and navigation buttons
- **Event Coordination**: Integrates pointer events, keyboard shortcuts, and extension hooks
- **State Management**: Tracks current index, zoom level, and UI activation state
- **Extension Integration**: Calls extension lifecycle hooks at key moments
## Constructor
```typescript
new VistaView(elements: string | VistaImgConfig[], options?: VistaOpt)
```
Creates a new VistaView instance.
**Parameters:**
- `elements`: Either a CSS selector string or an array of [image configurations](/api-reference/types#vistaimgconfig)
- `options`: Optional configuration object (see [VistaOpt](/api-reference/types#vistaopt))
**Example:**
```typescript
// Using CSS selector
const viewer = new VistaView('.gallery-item', {
maxZoomLevel: 3,
preloads: 2,
});
// Using configuration array
const viewer = new VistaView([
{ src: 'image1.jpg', alt: 'First image' },
{ src: 'image2.jpg', alt: 'Second image' },
]);
```
## Public Properties
### options
```typescript
options: VistaOpt;
```
The merged configuration options for this instance. Combines user-provided options with [DefaultOptions](/api-reference/lifecycle#defaultoptions).
See [VistaOpt](/api-reference/types#vistaopt) for complete type definition.
### state
```typescript
state: VistaState;
```
The current state manager containing:
- `currentIndex`: Current image index
- `elmLength`: Total number of images
- `zoomedIn`: Whether the current image is zoomed
- `extensions`: Set of registered extensions
- `children`: Current DOM elements and VistaBox instances
- `abortController`: For canceling transitions
See [VistaState](/api-reference/classes/vistastate) for complete documentation.
### imageContainer
```typescript
imageContainer: HTMLElement | null;
```
Reference to the DOM element containing the image elements. `null` when the lightbox is closed.
### externalPointerListener
```typescript
externalPointerListener: ((e: VistaExternalPointerListenerArgs) => void)[]
```
Array of external pointer event listeners registered via `registerPointerListener()`. Used by extensions to hook into pointer events.
See [VistaExternalPointerListenerArgs](/api-reference/types#vistaexternalpointerlistenerargs) for the event argument type.
## Public Methods
### open()
```typescript
open(startIndex?: number): void
```
Opens the lightbox at the specified image index.
**Parameters:**
- `startIndex`: The index of the image to display first (default: `0`)
**Behavior:**
- Prevents opening if another VistaView instance is already open
- Prevents body scrolling
- Creates and injects the lightbox DOM structure
- Sets up event handlers and keyboard listeners
- Calls `onOpen` event callback and extension hooks
- Supports negative indices and values beyond the array length (wraps around)
**Example:**
```typescript
const viewer = new VistaView('.gallery-item');
viewer.open(2); // Opens at the third image
```
### close()
```typescript
close(animate?: boolean): Promise
```
Closes the lightbox and cleans up resources.
**Parameters:**
- `animate`: Whether to animate the close transition (default: `true`)
**Behavior:**
- Waits for close animation to complete (if `animate` is `true`)
- Removes DOM elements and event handlers
- Destroys all VistaBox instances
- Restores body scrolling
- Calls `onClose` event callback and extension hooks
- Resets `GlobalVistaState`
**Example:**
```typescript
// Close with animation
await viewer.close();
// Close immediately without animation
await viewer.close(false);
```
### destroy()
```typescript
destroy(): void
```
Completely destroys the VistaView instance and removes all event listeners.
**Behavior:**
- Closes the lightbox without animation
- Removes click listeners from trigger elements
- Clears external pointer listeners
- Cannot be reopened after destruction
**Example:**
```typescript
viewer.destroy();
// viewer is now unusable
```
### next()
```typescript
next(): void
```
Navigates to the next image in the sequence.
**Behavior:**
- Wraps around to the first image after the last one
- Triggers transition animation
- Calls `onImageView` event callback
**Example:**
```typescript
viewer.next();
```
### prev()
```typescript
prev(): void
```
Navigates to the previous image in the sequence.
**Behavior:**
- Wraps around to the last image when at the first one
- Triggers transition animation
- Calls `onImageView` event callback
**Example:**
```typescript
viewer.prev();
```
### view()
```typescript
view(index: number, via?: { next: boolean; prev: boolean }): void
```
Jumps to a specific image by index.
**Parameters:**
- `index`: The target image index
- `via`: Optional object indicating navigation direction (used internally)
**Behavior:**
- Supports negative indices and values beyond array length (wraps around)
- Aborts any in-progress transition
- Calls `onImageView` event callback
- Handles rapid navigation with optimized transitions
**Example:**
```typescript
viewer.view(5); // Jump to 6th image
viewer.view(-1); // Jump to last image
```
### zoomIn()
```typescript
zoomIn(): void
```
Zooms in on the current image by a factor of 1.68x.
**Behavior:**
- Respects `maxZoomLevel` option
- Throttled to prevent excessive calls (222ms)
- Disables zoom-in button when at maximum zoom
- Can be disabled via `deactivateUi(['zoomIn'])`
**Example:**
```typescript
viewer.zoomIn();
```
### zoomOut()
```typescript
zoomOut(): void
```
Zooms out of the current image by a factor of 0.68x.
**Behavior:**
- Returns to minimum zoom (fit to viewport)
- Throttled to prevent excessive calls (222ms)
- Disables zoom-out button when at minimum zoom
- Can be disabled via `deactivateUi(['zoomOut'])`
**Example:**
```typescript
viewer.zoomOut();
```
### getCurrentIndex()
```typescript
getCurrentIndex(): number
```
Returns the current image index.
**Returns:** The zero-based index of the currently displayed image, or `-1` if closed.
**Example:**
```typescript
const index = viewer.getCurrentIndex();
console.log(`Viewing image ${index + 1}`);
```
### reset()
```typescript
reset(): void
```
Recalculates the image list and reattaches click listeners.
**Behavior:**
- Queries the DOM for elements matching the selector (if using string selector)
- Updates `state.elmLength`
- Removes and re-adds click event listeners
**Use Case:** Call this if the DOM has changed (elements added/removed) and you need to update the gallery.
**Example:**
```typescript
// After dynamically adding more images to the page
document.querySelector('.gallery').innerHTML += 'New';
viewer.reset();
```
### qs()
```typescript
qs(selector: string): T | null
```
Queries for an element within the lightbox root element.
**Parameters:**
- `selector`: CSS selector string
**Returns:** The first matching element or `null`
**Example:**
```typescript
const closeButton = viewer.qs('.vvw-close');
```
### qsOrigin()
```typescript
qsOrigin>(selector: string): T
```
Queries for elements in the document (not limited to lightbox root).
**Parameters:**
- `selector`: CSS selector string
**Returns:** NodeList of matching elements
**Example:**
```typescript
const galleryItems = viewer.qsOrigin>('.gallery-item');
```
### registerPointerListener()
```typescript
registerPointerListener(listener: (e: VistaExternalPointerListenerArgs) => void): void
```
Registers an external pointer event listener.
**Parameters:**
- `listener`: Function that receives [VistaExternalPointerListenerArgs](/api-reference/types#vistaexternalpointerlistenerargs) pointer event data
**Use Case:** Extensions can use this to respond to pointer events without directly managing event handlers.
**Example:**
```typescript
viewer.registerPointerListener((e) => {
console.log('Pointer event:', e.event, e.pointer);
console.log('Active pointers:', e.pointers.length);
});
```
### deactivateUi()
```typescript
deactivateUi(names: string[], requestBy?: VistaBox): void
```
Temporarily disables UI controls.
**Parameters:**
- `names`: Array of control names to disable (e.g., `['zoomIn', 'zoomOut']`)
- `requestBy`: Optional VistaBox instance making the request
**Behavior:**
- Sets `disabled` attribute on specified buttons
- Notifies extensions via `onDeactivateUi` hook
- Automatically reactivated before navigation or transitions
**Example:**
```typescript
// Disable zoom during a custom animation
viewer.deactivateUi(['zoomIn', 'zoomOut']);
```
## Related
- [Main Function](/api-reference/main-function) - The `vistaView()` function that creates [VistaView](/api-reference/classes/vistaview) instances
- [VistaOpt](/api-reference/types#vistaopt) - Configuration options type
- [Event Callbacks](/api-reference/events) - Events fired during lifecycle
- [Lifecycle Functions](/api-reference/lifecycle) - Customizable lifecycle hooks
:::tip
Use the [`vistaView()`](/api-reference/main-function) function (lowercase 'v') for creating instances. The `VistaView` class (capital 'V') is primarily used for TypeScript type imports in extensions and callbacks.
:::
---
# VistaState Class
Internal state management class for VistaView
Path: /api-reference/classes/vistastate
The `VistaState` class manages the internal state of a [VistaView](/api-reference/classes/vistaview) instance. It tracks the current state of the lightbox, including open/close status, current image, zoom level, and registered extensions.
## Overview
`VistaState` is automatically instantiated by [VistaView](/api-reference/classes/vistaview) and accessible via the [`state`](/api-reference/classes/vistaview#state) property. It provides a centralized location for all runtime state information.
**Access:**
```typescript
const viewer = new VistaView('.gallery-item');
viewer.open();
console.log(viewer.state.currentIndex); // Current image index
console.log(viewer.state.zoomedIn); // Zoom state
console.log(viewer.state.elmLength); // Total images
```
## Properties
### open
```typescript
open: boolean;
```
Whether the lightbox is currently open. `true` when the lightbox is visible, `false` when closed.
### settled
```typescript
settled: boolean;
```
Whether the open transition animation has completed. Useful for determining if the lightbox is fully settled after opening.
### closing
```typescript
closing: boolean;
```
Whether the lightbox is currently in the process of closing. `true` during the close transition animation.
### zoomedIn
```typescript
zoomedIn: boolean;
```
Whether the current image is zoomed beyond its minimum scale. `false` when the image is at fit-to-viewport scale, `true` when zoomed in.
### children
```typescript
children: {
htmls: HTMLElement[];
images: VistaBox[];
}
```
Current DOM elements and image instances in the view.
**Properties:**
- `htmls` - Array of HTML container elements (`.vvw-item` divs)
- `images` - Array of [VistaBox](/api-reference/classes/vistabox) instances (images or custom content)
The arrays include the current image plus preloaded images based on the `preloads` configuration option.
**Example:**
```typescript
const viewer = new VistaView('.gallery-item', { preloads: 2 });
viewer.open(5);
// With preloads: 2, children includes images at indices 3, 4, 5, 6, 7
console.log(viewer.state.children.images.length); // 5
console.log(viewer.state.children.images[2].index); // 5 (center image)
```
### currentIndex
```typescript
currentIndex: number;
```
Zero-based index of the currently displayed image. `-1` when the lightbox is closed.
**Example:**
```typescript
console.log(viewer.state.currentIndex); // 3 (viewing 4th image)
```
### elmLength
```typescript
elmLength: number;
```
Total number of images in the gallery. Updated automatically when `reset()` is called.
**Example:**
```typescript
const viewer = new VistaView('.gallery-item');
console.log(viewer.state.elmLength); // 10 (total images)
```
### abortController
```typescript
abortController: AbortController;
```
Controller for canceling in-progress transitions. Automatically reset before each navigation to abort the previous transition.
**Use Case:** Extensions can listen to the abort signal to cancel long-running operations when the user navigates quickly.
**Example:**
```typescript
const signal = viewer.state.abortController.signal;
signal.addEventListener('abort', () => {
console.log('Transition was canceled');
});
```
### isReducedMotion
```typescript
isReducedMotion: boolean;
```
Whether the user has requested reduced motion via system preferences. Detected from the `prefers-reduced-motion` media query.
**Example:**
```typescript
if (viewer.state.isReducedMotion) {
console.log('User prefers reduced motion');
}
```
### extensions
```typescript
extensions: Set;
```
Set of registered [extension](/api-reference/extensions) instances. Populated from the `extensions` configuration option.
**Example:**
```typescript
import { logger } from 'vistaview/extensions/logger';
const viewer = new VistaView('.gallery-item', {
extensions: [logger()],
});
console.log(viewer.state.extensions.size); // 1
```
## Related
- [VistaView Class](/api-reference/classes/vistaview) - Main controller class that uses VistaState
- [VistaExtension](/api-reference/types#vistaextension) - Extension interface type
- [Extensions](/api-reference/extensions) - Extension system documentation
---
# VistaPointers Class
Multi-pointer tracking system for touch and mouse interactions
Path: /api-reference/classes/vistapointers
The `VistaPointers` class provides a unified interface for tracking mouse and touch pointer events. It normalizes pointer data across different input types and manages multi-touch gestures.
## Overview
`VistaPointers` handles:
- Mouse, touch, and pen input tracking
- Multi-pointer gestures (pinch, pan)
- Pointer movement calculations
- Event normalization across input types
**Use Case:** Primarily used internally by [VistaView](/api-reference/classes/vistaview) for handling interactions. Extensions can access pointer data through event listeners.
## Public Properties
None - all properties are private.
## Public Methods
### constructor()
```typescript
constructor(args: VistaPointerArgs)
```
Creates a new pointer tracking system.
**Parameters:**
- `args.elm` - Element to attach listeners to (defaults to `document`)
- `args.listeners` - Array of [pointer listeners](/api-reference/types#vistapointerlistener)
**Example:**
```typescript
import { VistaPointers } from 'vistaview';
const pointers = new VistaPointers({
elm: element,
listeners: [
(e) => {
console.log('Pointer event:', e.event, e.pointers.length);
},
],
});
```
### startListeners()
```typescript
startListeners(): void
```
Starts listening to pointer events. Called automatically by constructor.
### removeListeners()
```typescript
removeListeners(): void
```
Removes all pointer event listeners. Call this when cleaning up.
**Example:**
```typescript
pointers.removeListeners();
```
### addEventListener()
```typescript
addEventListener(listener: VistaPointerListener): void
```
Adds a pointer event listener.
**Example:**
```typescript
pointers.addEventListener((e) => {
if (e.event === 'down') {
console.log('Pointer down at:', e.pointer.x, e.pointer.y);
}
});
```
### removeEventListener()
```typescript
removeEventListener(listener: VistaPointerListener): void
```
Removes a specific pointer event listener.
### getPointerDistance()
```typescript
getPointerDistance(p1: VistaPointer, p2: VistaPointer): number
```
Calculates the distance between two pointers. Useful for pinch-to-zoom gestures.
**Parameters:**
- `p1` - First [pointer](/api-reference/types#vistapointer)
- `p2` - Second [pointer](/api-reference/types#vistapointer)
**Returns:** Distance in pixels
**Example:**
```typescript
pointers.addEventListener((e) => {
if (e.pointers.length >= 2) {
const distance = pointers.getPointerDistance(e.pointers[0], e.pointers[1]);
console.log('Pinch distance:', distance);
}
});
```
### getCentroid()
```typescript
getCentroid(): { x: number; y: number } | null
```
Calculates the center point of all active pointers. Returns `null` if no pointers are active.
**Returns:** Center coordinates or `null`
**Example:**
```typescript
const center = pointers.getCentroid();
if (center) {
console.log('Center point:', center.x, center.y);
}
```
## Related
- [VistaPointer](/api-reference/types#vistapointer) - Pointer data type
- [VistaPointerListener](/api-reference/types#vistapointerlistener) - Listener function type
- [VistaExternalPointerListenerArgs](/api-reference/types#vistaexternalpointerlistenerargs) - Event arguments
---
## AI Integration
---
# AI Integration
Agent-ready tooling — MCP Server, Markdown for Agents, and LLMs.txt
Path: /ai-integration
VistaView's documentation is built for AI consumption. Agents and LLMs can access docs via three complementary mechanisms:
## LLMs.txt (via Context7)
A curated summary of all documentation in a single file. Ideal for LLM context windows.
- [`/llms.txt`](/llms.txt) — Concise overviews of each section
- [`/llms-full.txt`](/llms-full.txt) — Complete documentation in one file
- [Context7](https://context7.com/llmstxt/vistaview_jujiplay_llms_txt) — Preprocessed for common AI tools
## Markdown for Agents
Set the `Accept: text/markdown` header on any documentation URL to receive the page content as plain Markdown instead of HTML.
```sh
curl -H "Accept: text/markdown" https://vistaview.jujiplay.com/core/installation/
```
The response contains only the page's main content — no navigation, sidebars, or chrome.
## MCP Server
A JSON-RPC MCP server is available at [`POST /mcp`](/mcp) for programmatic access from AI agents and tools.
**Tools:**
| Tool | Description |
|---|---|
| `get_package_info` | Fetch npm package metadata for vistaview (or any package) |
| `get_build_status` | Get latest GitHub Actions build status |
| `search_docs` | Search across all documentation |
### Claude Desktop
Add to your `claude_desktop_config.json`:
```json
{
"mcpServers": {
"vistaview": {
"url": "https://vistaview.jujiplay.com/mcp"
}
}
}
```
### Any MCP Client
Configure with the endpoint URL:
```
https://vistaview.jujiplay.com/mcp
```
Protocol: JSON-RPC 2.0 over HTTP POST.
## Why Agent-Ready?
When building with VistaView, AI assistants can:
- Look up configuration options without leaving the IDE
- Verify the latest package version and compatibility
- Check build status when reporting issues
- Search documentation for specific features or APIs