A lightweight, customizable lightbox plugin for images, videos, iframes, and inline HTML. Inspired by FancyBox.
Full-featured lightbox with zero dependencies. Just drop in the CSS and JS.
Click any card below to open the lightbox. Each demo showcases a different content type.
<!-- CSS -->
<link rel="stylesheet" href="css/tglightbox.css">
<!-- JS -->
<script src="js/tglightbox.js"></script>
<a data-tglb="gallery" href="large.jpg" data-caption="Photo 1">
<img src="thumb.jpg" alt="Photo 1">
</a>
<a data-tglb="gallery" href="large2.jpg" data-caption="Photo 2">
<img src="thumb2.jpg" alt="Photo 2">
</a>
// Declarative — binds click handlers to all matching elements
TGLightbox.bind('[data-tglb]');
// Programmatic — open from JavaScript
TGLightbox.show([
{ src: 'image.jpg', caption: 'Photo 1' },
{ src: 'https://youtube.com/watch?v=xyz', type: 'youtube' },
{ src: 'video.mp4', type: 'video' },
{ src: 'https://example.com', type: 'iframe' },
{ src: '#my-element', type: 'inline' },
{ src: '/api/data', type: 'ajax' },
], { loop: true, thumbnails: true });
| Option | Type | Default | Description |
|---|---|---|---|
groupAll |
boolean | false | Merge all matching triggers into a single gallery, regardless of data-tglb value. |
startIndex |
number | 0 | Which slide to start on when opening. |
preload |
number | 2 | Number of adjacent slides to preload. |
keyboard |
boolean | true | Enable keyboard navigation (arrows, Escape, +/-, F). |
dragToClose |
boolean | true | Drag down to close on touch devices. |
clickOutsideClose |
boolean | true | Click on overlay to close. |
loop |
boolean | true | Infinite carousel loop. |
wheel |
boolean | true | Mouse wheel to navigate slides. |
zoom |
boolean | false | Enable zoom functionality. |
zoomMax |
number | 3 | Maximum zoom level. |
zoomStep |
number | 0.5 | Zoom increment per step. |
toolbar |
boolean | true | Show the toolbar (zoom, fullscreen, close). |
thumbnails |
boolean | false | Show thumbnail strip at the bottom. |
closeButton |
boolean | true | Show the close button in the toolbar. |
fullscreen |
boolean | true | Show the fullscreen button. |
icons |
object | {} | Custom icons for buttons. See Icons tab. |
animationDuration |
number | 300 | Animation duration in milliseconds. |
mainClass |
string | '' | Extra CSS class added to the overlay element. |
on |
object | {} | Event callbacks. See Events tab. |
Each slide is defined by a plain object (programmatic API) or by data attributes on the trigger element (declarative API). The properties below apply to individual slides, not the lightbox as a whole.
| Property | Data attribute | Type | Description |
|---|---|---|---|
src |
href or data-src |
string | URL or selector for the content. Required. |
type |
data-type |
string | Content type: image, youtube, vimeo, video, iframe, inline, ajax. Auto-detected from src if omitted. |
caption |
data-caption |
string | Caption text shown below the slide. |
thumbSrc |
data-thumb |
string | Thumbnail image URL for the thumbnail strip. Falls back to src. |
aspectRatio |
data-aspect-ratio |
string | Aspect ratio for iframe / YouTube / Vimeo embeds. Accepts 16:9, 4:3, 21:9, 1:1, or a decimal like 1.7778. Defaults to 16:9. |
width |
data-width |
number | string | Fixed width for iframe / YouTube / Vimeo embeds. Accepts a pixel number (900) or any CSS value (80vw). The embed is still height-constrained by the viewport. |
width / height |
— | number | Intrinsic pixel dimensions passed to <img> and <video> elements. Programmatic API only. |
mimeType |
— | string | MIME type hint for HTML5 video, e.g. video/mp4. Programmatic API only. |
YouTube, Vimeo, and iframe slides are sized to fill the viewport while preserving their aspect ratio. Use data-aspect-ratio to change the ratio and data-width to cap the width.
<!-- 16:9 (default for all embeds) -->
<a href="https://youtube.com/watch?v=ID"
data-type="youtube"
data-aspect-ratio="16:9">Watch</a>
<!-- 4:3 for older video -->
<a href="https://vimeo.com/123456"
data-type="vimeo"
data-aspect-ratio="4:3">Watch</a>
<!-- Ultra-wide embed -->
<a href="https://example.com"
data-type="iframe"
data-aspect-ratio="21:9">Open</a>
<!-- Fixed 900 px wide, 16:9 tall -->
<a href="https://example.com"
data-type="iframe"
data-aspect-ratio="16:9"
data-width="900">Open</a>
TGLightbox.show([
// YouTube — 16:9
{ src: 'https://youtube.com/watch?v=ID', type: 'youtube', aspectRatio: '16:9' },
// Vimeo — 4:3
{ src: 'https://vimeo.com/123456', type: 'vimeo', aspectRatio: '4:3' },
// iframe — capped at 900 px wide
{ src: 'https://example.com', type: 'iframe', aspectRatio: '16:9', width: 900 },
]);
data-aspect-ratio="16:9" // ratio with colon
data-aspect-ratio="16/9" // ratio with slash
data-aspect-ratio="1.7778" // decimal
data-aspect-ratio="1:1" // square
data-aspect-ratio="21:9" // ultra-wide / cinematic
| Event | Callback Arguments | Description |
|---|---|---|
onInit |
(instance) | Fired when the instance is created and DOM is ready. |
onOpen |
(instance, slide) | Fired when the lightbox begins opening. Return false to block. |
onOpened |
(instance, slide) | Fired after the open animation completes. |
onChange |
(instance, newSlide, prevSlide) | Fired when slide changes. Return false to block. |
onChanged |
(instance, slide) | Fired after slide change animation completes. |
onLoad |
(instance, slide) | Fired when content finishes loading. |
onError |
(instance, slide, error) | Fired when content fails to load. |
onZoom |
(instance, slide, zoomLevel) | Fired when zoom level changes. |
onClose |
(instance) | Fired when the lightbox begins closing. Return false to block. |
onClosed |
(instance) | Fired after the close animation completes. |
onFullscreen |
(instance, isFullscreen) | Fired when fullscreen is toggled. |
onSwipe |
(instance, direction) | Fired when a swipe gesture is detected. |
TGLightbox.bind('[data-tglb]', {
on: {
open: (instance, slide) => {
console.log('Opened:', slide.src);
},
change: (instance, newSlide, prevSlide) => {
console.log('Changed to:', newSlide.index);
},
close: (instance) => {
console.log('Closing lightbox');
},
},
});
| Method | Arguments | Description |
|---|---|---|
TGLightbox.bind() |
(selector, options) | Bind click handlers to all elements matching the selector. |
TGLightbox.show() |
(slides, options) | Create and open a new lightbox instance programmatically. |
TGLightbox.close() |
() | Close the topmost active instance. |
TGLightbox.destroy() |
() | Destroy all instances and clean up event listeners. |
TGLightbox.getInstance() |
() | Get the topmost active instance reference. |
instance.next() |
() | Navigate to the next slide. |
instance.prev() |
() | Navigate to the previous slide. |
instance.jumpTo() |
(index) | Jump to a specific slide by index. |
instance.close() |
() | Close this instance. |
instance.on() |
(event, handler) | Subscribe to an event on this instance. |
instance.off() |
(event, handler) | Unsubscribe from an event. |
instance.zoomIn() |
() | Zoom in by one step. |
instance.zoomOut() |
() | Zoom out by one step. |
instance.resetZoom() |
() | Reset zoom to 1x. |
instance.toggleFullscreen() |
() | Toggle fullscreen mode. |
Every button icon can be customized. Pass a string to the icons option — it can be a CSS class (Font Awesome), raw HTML (image/SVG), or a unicode character.
TGLightbox.bind('[data-tglb]', {
icons: {
close: 'fas fa-times',
prev: 'fas fa-chevron-left',
next: 'fas fa-chevron-right',
zoomIn: 'fas fa-search-plus',
zoomOut: 'fas fa-search-minus',
fullscreen: 'fas fa-expand',
},
});
TGLightbox.bind('[data-tglb]', {
icons: {
close: '<img src="icons/close.svg" alt="Close">',
prev: '<img src="icons/prev.svg" alt="Previous">',
next: '<img src="icons/next.svg" alt="Next">',
},
});
TGLightbox.bind('[data-tglb]', {
icons: {
close: '×',
prev: '←',
next: '→',
zoomIn: '+',
zoomOut: '−',
},
});
| Icon Key | Button | Default |
|---|---|---|
close |
Close button (top right) | × (CSS pseudo-element) |
prev |
Previous arrow (left side) | ‹ (CSS pseudo-element) |
next |
Next arrow (right side) | › (CSS pseudo-element) |
zoomIn |
Zoom in button (toolbar) | + (CSS pseudo-element) |
zoomOut |
Zoom out button (toolbar) | − (CSS pseudo-element) |
fullscreen |
Fullscreen toggle (toolbar) | ⤢ (CSS pseudo-element) |
play |
Video play button overlay | ▶ (CSS pseudo-element) |
All visual properties are controlled via CSS custom properties. Override them in your stylesheet to match your design.
| Variable | Default | Description |
|---|---|---|
--tglb-bg |
rgba(0, 0, 0, 0.92) | Overlay background color |
--tglb-border-radius |
8px | Border radius for content and buttons |
--tglb-toolbar-bg |
rgba(0, 0, 0, 0.6) | Toolbar button background |
--tglb-caption-color |
#fff | Caption text color |
--tglb-caption-bg |
rgba(0, 0, 0, 0.8) | Caption background |
--tglb-caption-font-size |
14px | Caption text size |
--tglb-transition-duration |
0.3s | Animation speed |
--tglb-transition-easing |
cubic-bezier(0.4, 0, 0.2, 1) | Animation timing function |
--tglb-z-index |
9999 | Overlay z-index |
--tglb-icon-size |
40px | Toolbar button size |
--tglb-icon-color |
#fff | Icon color |
--tglb-thumb-size |
60px | Thumbnail dimensions |
--tglb-thumb-gap |
6px | Space between thumbnails |
--tglb-thumb-active-border |
#fff | Active thumbnail border color |
--tglb-overlay-blur |
8px | Backdrop blur amount |
--tglb-spinner-color |
rgba(255, 255, 255, 0.8) | Loading spinner color |
:root {
--tglb-bg: rgba(10, 10, 30, 0.95);
--tglb-border-radius: 12px;
--tglb-icon-color: #60a5fa;
--tglb-caption-bg: rgba(10, 10, 30, 0.8);
--tglb-thumb-active-border: #60a5fa;
--tglb-overlay-blur: 12px;
}
| Key | Action |
|---|---|
← | Previous slide |
→ | Next slide |
Escape | Close lightbox |
+ / = | Zoom in |
- | Zoom out |
0 | Reset zoom |
F | Toggle fullscreen |