aetherbox
v0.1.0
Published
Lightweight ES Module lightbox — images, video, HTML, zoom/pan, carousel, i18n
Maintainers
Readme
Aetherbox
A lightweight, zero-dependency-at-runtime ES Module lightbox for images, video, iframes, and arbitrary HTML — with pinch/zoom, swipe carousel, thumbnails, and i18n out of the box.
Features
- 🖼️ Images, video, iframes, and raw HTML in one gallery
- 🎬 Built-in providers for YouTube, Vimeo, VK Video, and Rutube — just drop in a link
- 🔍 Pinch-to-zoom and pan on images (mouse wheel, double-click, touch gestures)
- 👉 Swipe navigation between slides on touch devices
- 🖱️ Drag-to-dismiss style preview swipe
- 🧵 Thumbnail strip with click-to-jump
- 🌍 i18n-ready — English built in, Russian available as an optional import, easy to add your own
- 📦 Tree-shakeable ESM — no bundled CSS-in-JS, no jQuery, no runtime dependencies beyond a small peer dependency for gestures
- ♿ Accessible — proper
dialogrole,aria-modal, keyboard navigation (←/→/Esc/+/-/0)
Demo
<a href="/photos/01-full.jpg" data-thumb="/photos/01-thumb.jpg" data-aetherbox data-aetherbox-group="gallery">
<img src="/photos/01-thumb.jpg" alt="">
</a>
<a href="/photos/02-full.jpg" data-thumb="/photos/02-thumb.jpg" data-aetherbox data-aetherbox-group="gallery">
<img src="/photos/02-thumb.jpg" alt="">
</a>import { Aetherbox } from 'aetherbox';
import 'aetherbox/css';
new Aetherbox().autoInit();That's it — clicking any linked thumbnail opens the gallery.
Installation
npm install aetherbox @use-gesture/vanilla
@use-gesture/vanillais a peer dependency used for pinch/zoom/swipe gestures. It is not bundled, so you install it once and Aetherbox uses your copy.
Usage
Auto-binding from markup (declarative)
Mark any link or element with data-aetherbox. Group related items with a shared data-aetherbox-group so they form a single gallery/carousel.
<a href="/img/cat.jpg" data-aetherbox data-aetherbox-group="pets" data-title="My cat"></a>
<a href="https://youtu.be/dQw4w9WgXcQ" data-aetherbox data-aetherbox-group="pets" data-title="A video"></a>Supported data-* attributes per element:
| Attribute | Description |
|------------------------|------------------------------------------------------------|
| href / data-src | Source URL (image, video file, embeddable link, or iframe) |
| data-type | Force a type: image, video, iframe, html. Auto-detected if omitted (including YouTube/Vimeo/VK/Rutube links). |
| data-title | Caption title |
| data-description | Caption description |
| data-thumb | Thumbnail image shown in the strip (falls back to src for <img>) |
| data-html | Raw HTML content, used when data-type="html" |
| data-aetherbox-group | Groups elements into one gallery (omit for a single standalone item) |
import { Aetherbox } from 'aetherbox';
import 'aetherbox/css';
const lightbox = new Aetherbox({
selector: '[data-aetherbox]', // default
});
lightbox.autoInit();Programmatic API
import { Aetherbox } from 'aetherbox';
import 'aetherbox/css';
const lightbox = new Aetherbox({
loop: true,
keyboard: true,
thumbnails: true,
counter: true,
closeOnBackdrop: true,
zoom: true,
zoomMin: 1,
zoomMax: 5,
zoomStep: 0.6,
zoomButtons: true,
});
lightbox.add([
{ src: '/img/1.jpg', title: 'First image' },
{ src: 'https://youtu.be/dQw4w9WgXcQ', title: 'A video' },
{ type: 'html', html: '<p>Custom content</p>' },
]);
lightbox.open(0);Methods
| Method | Description |
|------------------------------|----------------------------------------------------------------|
| add(item \| item[]) | Append one or more items |
| remove(index) | Remove an item by index |
| clear() | Remove all items |
| open(index = 0) | Open the lightbox at a given slide |
| close() | Close the lightbox |
| goto(index) | Jump to a specific slide while open |
| next() / prev() | Navigate slides |
| loadFrom(url, fetchOpts?) | Fetch a JSON array of items and add() them |
| autoInit(root = document) | Scan the DOM for [data-aetherbox] elements and bind them |
| destroy() | Tear down the instance and remove listeners |
Events
Aetherbox extends a small EventEmitter. Subscribe with .on(event, handler):
lightbox.on('open', ({ index }) => {});
lightbox.on('change', ({ index, prev, item }) => {});
lightbox.on('shown', ({ index, item }) => {});
lightbox.on('error', ({ index, item, error }) => {});
lightbox.on('close', () => {});
lightbox.on('destroy', () => {});
lightbox.on('loadstart', ({ url }) => {});
lightbox.on('loadend', ({ url, count }) => {});
lightbox.on('loaderror', ({ url, error }) => {});Item shape
{
src: string; // URL — image, video file, embeddable link, or iframe src
type?: 'image' | 'video' | 'iframe' | 'html'; // auto-detected if omitted
title?: string;
description?: string;
thumb?: string; // thumbnail URL for the thumbnail strip
html?: string; // used when type === 'html'
width?: string | number; // for video/iframe frame sizing
height?: string | number;
}Video providers
Links matching these patterns are auto-detected and embedded — no extra config:
- YouTube (
youtube.com,youtu.be) - Vimeo (
vimeo.com) - VK Video (
vkvideo.ru,vk.com/video,vk.com/clip) - Rutube (
rutube.ru)
Internationalization
English is built in. To use another language:
import { Aetherbox } from 'aetherbox';
import { ru } from 'aetherbox/locale/ru';
import 'aetherbox/css';
const lightbox = new Aetherbox({ locale: ru });You can also override individual strings:
new Aetherbox({ locale: { ...ru, close: 'Х' } });Want to add a new language? Copy src/locale/en.js, translate the values, and either bundle it in your fork or pass it in directly via locale.
Keyboard shortcuts
| Key | Action |
|-----------|------------------|
| ← / → | Previous / next |
| Esc | Close |
| + / - | Zoom in / out |
| 0 | Reset zoom |
Styling
Import the default styles:
import 'aetherbox/css';The visual design ("aether" theme) is plain CSS with custom properties, so you can override colors, spacing, and timing by targeting .ab-* classes or redefining CSS variables in your own stylesheet loaded after aetherbox/css.
Browser support
Modern evergreen browsers (ES2020+). No IE11 support.
License
MIT © legkomedia
Aetherbox (на русском)
Лёгкий ES-модульный лайтбокс без зависимостей в рантайме — для изображений, видео, iframe и произвольного HTML, со встроенным zoom/pan, свайп-каруселью, миниатюрами и поддержкой нескольких языков.
Возможности
- 🖼️ Изображения, видео, iframe и HTML в одной галерее
- 🎬 Готовые провайдеры видео: YouTube, Vimeo, VK Видео, Rutube — достаточно вставить ссылку
- 🔍 Zoom и pan на изображениях (колесо мыши, двойной клик, тач-жесты)
- 👉 Свайп-навигация между слайдами на тач-устройствах
- 🖱️ Drag-preview при смене слайдов
- 🧵 Полоса миниатюр с переходом по клику
- 🌍 Готов к i18n — английский встроен, русский доступен опционально, легко добавить свой язык
- 📦 Tree-shakeable ESM — без CSS-in-JS, без jQuery, без рантайм-зависимостей (кроме небольшого peer-пакета для жестов)
- ♿ Доступность — корректная роль
dialog,aria-modal, навигация с клавиатуры (←/→/Esc/+/-/0)
Демо
<a href="/photos/01-full.jpg" data-thumb="/photos/01-thumb.jpg" data-aetherbox data-aetherbox-group="gallery">
<img src="/photos/01-thumb.jpg" alt="">
</a>
<a href="/photos/02-full.jpg" data-thumb="/photos/02-thumb.jpg" data-aetherbox data-aetherbox-group="gallery">
<img src="/photos/02-thumb.jpg" alt="">
</a>import { Aetherbox } from 'aetherbox';
import 'aetherbox/css';
new Aetherbox().autoInit();Готово — клик по любой миниатюре открывает галерею.
Установка
npm install aetherbox @use-gesture/vanilla
@use-gesture/vanilla— peer-зависимость, используемая для жестов zoom/pan/swipe. Она не встраивается в сборку, поэтому устанавливается один раз отдельно.
Использование
Автоматическая привязка из разметки (декларативно)
Помечайте ссылки или элементы атрибутом data-aetherbox. Объединяйте связанные элементы общим data-aetherbox-group, чтобы они образовали одну галерею/карусель.
<a href="/img/cat.jpg" data-aetherbox data-aetherbox-group="pets" data-title="Мой кот"></a>
<a href="https://youtu.be/dQw4w9WgXcQ" data-aetherbox data-aetherbox-group="pets" data-title="Видео"></a>Поддерживаемые data-* атрибуты:
| Атрибут | Описание |
|-------------------------|------------------------------------------------------------------|
| href / data-src | URL источника (картинка, видеофайл, ссылка для embed или iframe) |
| data-type | Принудительный тип: image, video, iframe, html. Если не указан — определяется автоматически (включая ссылки YouTube/Vimeo/VK/Rutube). |
| data-title | Заголовок подписи |
| data-description | Текст описания |
| data-thumb | Миниатюра для полосы превью (для <img> берётся src, если не указано) |
| data-html | Произвольный HTML, используется при data-type="html" |
| data-aetherbox-group | Группирует элементы в одну галерею (если не указан — отдельный элемент) |
import { Aetherbox } from 'aetherbox';
import 'aetherbox/css';
const lightbox = new Aetherbox({
selector: '[data-aetherbox]', // по умолчанию
});
lightbox.autoInit();Программный API
import { Aetherbox } from 'aetherbox';
import 'aetherbox/css';
const lightbox = new Aetherbox({
loop: true,
keyboard: true,
thumbnails: true,
counter: true,
closeOnBackdrop: true,
zoom: true,
zoomMin: 1,
zoomMax: 5,
zoomStep: 0.6,
zoomButtons: true,
});
lightbox.add([
{ src: '/img/1.jpg', title: 'Первая картинка' },
{ src: 'https://youtu.be/dQw4w9WgXcQ', title: 'Видео' },
{ type: 'html', html: '<p>Произвольный контент</p>' },
]);
lightbox.open(0);Методы
| Метод | Описание |
|--------------------------------|--------------------------------------------------------------------|
| add(item \| item[]) | Добавить один или несколько элементов |
| remove(index) | Удалить элемент по индексу |
| clear() | Удалить все элементы |
| open(index = 0) | Открыть лайтбокс на нужном слайде |
| close() | Закрыть лайтбокс |
| goto(index) | Перейти на слайд, пока лайтбокс открыт |
| next() / prev() | Навигация по слайдам |
| loadFrom(url, fetchOpts?) | Загрузить JSON-массив элементов и добавить через add() |
| autoInit(root = document) | Найти [data-aetherbox] элементы в DOM и привязать их |
| destroy() | Уничтожить инстанс и снять слушатели |
События
Aetherbox наследует небольшой EventEmitter. Подписка через .on(event, handler):
lightbox.on('open', ({ index }) => {});
lightbox.on('change', ({ index, prev, item }) => {});
lightbox.on('shown', ({ index, item }) => {});
lightbox.on('error', ({ index, item, error }) => {});
lightbox.on('close', () => {});
lightbox.on('destroy', () => {});
lightbox.on('loadstart', ({ url }) => {});
lightbox.on('loadend', ({ url, count }) => {});
lightbox.on('loaderror', ({ url, error }) => {});Структура элемента
{
src: string; // URL — картинка, видеофайл, embed-ссылка или iframe src
type?: 'image' | 'video' | 'iframe' | 'html'; // если не указан — определяется автоматически
title?: string;
description?: string;
thumb?: string; // URL миниатюры для полосы превью
html?: string; // используется при type === 'html'
width?: string | number; // размер рамки для video/iframe
height?: string | number;
}Видео-провайдеры
Ссылки следующих видов определяются автоматически и встраиваются без доп. настройки:
- YouTube (
youtube.com,youtu.be) - Vimeo (
vimeo.com) - VK Видео (
vkvideo.ru,vk.com/video,vk.com/clip) - Rutube (
rutube.ru)
Локализация
Английский встроен по умолчанию. Чтобы использовать другой язык:
import { Aetherbox } from 'aetherbox';
import { ru } from 'aetherbox/locale/ru';
import 'aetherbox/css';
const lightbox = new Aetherbox({ locale: ru });Можно переопределить отдельные строки:
new Aetherbox({ locale: { ...ru, close: 'Х' } });Хотите добавить новый язык? Скопируйте src/locale/en.js, переведите значения и либо подключите файл в своём форке, либо передайте объект напрямую через locale.
Горячие клавиши
| Клавиша | Действие |
|-----------|-------------------|
| ← / → | Назад / вперёд |
| Esc | Закрыть |
| + / - | Увеличить / уменьшить |
| 0 | Сбросить зум |
Стили
Подключите стандартные стили:
import 'aetherbox/css';Визуальное оформление (тема "aether") — это обычный CSS с переменными, поэтому можно переопределить цвета, отступы и тайминги, переписав классы .ab-* или CSS-переменные в своём стиле, подключённом после aetherbox/css.
Поддержка браузеров
Современные браузеры (ES2020+). Без поддержки IE11.
Лицензия
MIT © legkomedia
