Lightbox
Un componente lightbox de galería de imágenes y vídeos a pantalla completa, con @reelkit/react-lightbox.
Características
Instalación
npm install @reelkit/react-lightbox @reelkit/react lucide-reactNo olvides importar los estilos:
import '@reelkit/react-lightbox/styles.css';Iconos
Los controles por defecto usan lucide-react para los iconos. Si prefieres otra librería de iconos, usa renderControls y renderNavigation para poner los tuyos.
Inicio rápido
El componente LightboxOverlay muestra imágenes a pantalla completa. Pásale un array de objetos LightboxItem y controla su visibilidad con un índice que puede ser nulo.
import { useState } from 'react';
import { LightboxOverlay, type LightboxItem } from '@reelkit/react-lightbox';
import '@reelkit/react-lightbox/styles.css';
const images: LightboxItem[] = [
{
src: 'https://example.com/image1.jpg',
title: 'Sunset',
description: 'Beautiful sunset over the ocean',
},
{
src: 'https://example.com/image2.jpg',
title: 'Mountains',
},
];
function App() {
const [index, setIndex] = useState<number | null>(null);
return (
<>
{images.map((img, i) => (
<img
key={i}
src={img.src}
onClick={() => setIndex(i)}
/>
))}
<LightboxOverlay
isOpen={index !== null}
images={images}
initialIndex={index ?? 0}
onClose={() => setIndex(null)}
/>
</>
);
}Demo en vivo
Pulsa una miniatura para abrir el lightbox. Usa las flechas o desliza para navegar.
Slides de vídeo (opcionales)
El vídeo es totalmente opcional y admite tree-shaking: si solo usas imágenes, el bundle no crece nada. Importa useVideoSlideRenderer y conecta lo que devuelve a LightboxOverlay. El hook gestiona solo los estados de carga, el sonido y el ciclo de vida del vídeo.
import {
LightboxOverlay,
useVideoSlideRenderer,
type LightboxItem,
} from '@reelkit/react-lightbox';
import '@reelkit/react-lightbox/styles.css';
const items: LightboxItem[] = [
{ src: '/photo.jpg', title: 'Photo' },
{
src: '/clip.mp4',
type: 'video',
poster: '/clip-thumb.jpg',
title: 'Video Clip',
},
];
function Gallery() {
const [index, setIndex] = useState<number | null>(null);
const isOpen = index !== null;
const { renderSlide, renderControls, SoundProvider } =
useVideoSlideRenderer(items, isOpen);
return (
<SoundProvider>
{/* thumbnails… */}
<LightboxOverlay
isOpen={isOpen}
images={items}
initialIndex={index ?? 0}
onClose={() => setIndex(null)}
renderSlide={renderSlide}
renderControls={renderControls}
/>
</SoundProvider>
);
}Cómo funciona
- El hook devuelve
SoundProvider: envuelve el overlay con él para que funcione el silencio - Los vídeos se reproducen solos (en silencio por defecto) cuando el slide se activa
- Se reutiliza un mismo elemento de vídeo entre slides para que el sonido no se corte en iOS
- El botón de sonido aparece solo en los slides de vídeo, con un interruptor de silencio reactivo
- Los elementos sin
type: 'video'se renderizan como imágenes (compatible con versiones anteriores)
Personalización
Controles propios
Usa renderControls para sustituir el botón de cerrar, el contador y el botón de pantalla completa por defecto. Combínalo con los subcomponentes exportados:
import {
LightboxOverlay,
CloseButton,
Counter,
FullscreenButton,
} from '@reelkit/react-lightbox';
<LightboxOverlay
isOpen={isOpen}
images={images}
onClose={handleClose}
renderControls={({ onClose, activeIndex, count, isFullscreen, onToggleFullscreen }) => (
<div style={{ position: 'absolute', top: 12, left: 16, right: 16, display: 'flex', justifyContent: 'space-between', zIndex: 10 }}>
<Counter currentIndex={activeIndex} count={count} />
<div>
<FullscreenButton isFullscreen={isFullscreen} onToggle={onToggleFullscreen} />
<CloseButton onClick={onClose} />
</div>
</div>
)}
/>Overlay de información propio
Usa renderInfo para sustituir el degradado por defecto con el título y la descripción, o pasa renderInfo={() => null} para ocultarlo del todo:
<LightboxOverlay
isOpen={isOpen}
images={images}
onClose={handleClose}
renderInfo={({ item, index }) => (
<div style={{ position: 'absolute', bottom: 0, left: 0, right: 0, padding: 16, background: 'linear-gradient(transparent, rgba(0,0,0,0.8))', color: '#fff', zIndex: 10 }}>
<h3>{item.title}</h3>
<p>{item.description}</p>
</div>
)}
/>Navegación propia
Usa renderNavigation para sustituir las flechas de anterior y siguiente por defecto:
<LightboxOverlay
isOpen={isOpen}
images={images}
onClose={handleClose}
renderNavigation={({ onPrev, onNext, activeIndex, count }) => (
<div style={{ position: 'absolute', bottom: 24, left: '50%', transform: 'translateX(-50%)', display: 'flex', gap: 12, zIndex: 10 }}>
<button onClick={onPrev} disabled={activeIndex === 0}>Prev</button>
<span>{activeIndex + 1} / {count}</span>
<button onClick={onNext} disabled={activeIndex === count - 1}>Next</button>
</div>
)}
/>Slide propio
Usa renderSlide para un contenido del slide totalmente propio. Devuelve null para usar el slide de imagen por defecto:
<LightboxOverlay
isOpen={isOpen}
images={images}
onClose={handleClose}
renderSlide={({ item, index, size, isActive, onReady, onError }) => {
// Custom CTA on last slide
if (index === images.length - 1) {
return (
<div style={{ width: size[0], height: size[1], display: 'flex', alignItems: 'center', justifyContent: 'center', color: '#fff' }}>
<h2>View all photos</h2>
</div>
);
}
return null; // default image slide
}}
/>Carga de contenido y gestión de errores
El lightbox sigue el estado de carga y de error de cada slide. Mientras el contenido se carga se muestra un spinner; con un medio que falla aparece un icono de imagen rota. Las URLs con error se guardan en caché, así que al volver se muestra el error al instante sin reintentar.
Callbacks del ciclo de vida
Si usas renderSlide, llama a estos callbacks para controlar el indicador de carga:
| Callback | Cuándo llamarlo |
|---|---|
onReady | La imagen se ha cargado o el vídeo ha empezado a reproducirse. Limpia los estados de carga y de error. |
onWaiting | El vídeo está cargando a mitad de la reproducción. Muestra el indicador de carga. |
onError | El contenido no se ha podido cargar. Muestra el overlay de error y guarda la URL en caché como rota. |
// Inside renderSlide — wire callbacks to your custom media
renderSlide={({ item, index, size, isActive, onReady, onWaiting, onError }) => (
<div style={{ width: size[0], height: size[1] }}>
{item.type === 'video' ? (
<video
src={item.src}
poster={item.poster}
autoPlay={isActive}
onCanPlay={onReady}
onWaiting={onWaiting}
onError={onError}
style={{ width: '100%', height: '100%', objectFit: 'contain' }}
/>
) : (
<img
src={item.src}
onLoad={onReady}
onError={onError}
style={{ width: '100%', height: '100%', objectFit: 'contain' }}
/>
)}
</div>
)}Interfaz de carga y de error propia
Sustituye el spinner y el icono de error por defecto por componentes propios:
<LightboxOverlay
isOpen={isOpen}
images={images}
onClose={() => setIsOpen(false)}
renderLoading={({ item, activeIndex }) => (
<div style={{
position: 'absolute', inset: 0, zIndex: 10,
display: 'flex', alignItems: 'center', justifyContent: 'center',
color: '#fff', fontSize: 14,
}}>
Loading image {activeIndex + 1}...
</div>
)}
renderError={({ item, activeIndex }) => (
<div style={{
position: 'absolute', inset: 0, zIndex: 10,
display: 'flex', flexDirection: 'column',
alignItems: 'center', justifyContent: 'center',
gap: 12, color: 'rgba(255,255,255,0.5)',
}}>
<span style={{ fontSize: 48 }}>!</span>
<span>Failed to load content</span>
</div>
)}
/>Estado en la URL
Ver la demo en vivo →LightboxUrlOverlay es un componente aparte cuyo estado abierto vive en la barra de direcciones. Crea un controlador con useOverlayUrlState de @reelkit/react y pásalo como controller: la galería se abre sola cuando el parámetro nombra un slide y se cierra cuando desaparece. Los enlaces se pueden compartir y el botón de volver cierra la galería en lugar de salir de la página.
Claves incluidas
Puedes apuntar a los slides con una clave incluida: pasa con spread urlIndexKey (por posición) o urlStableIdKey (por un id estable) al controlador; las dos se reexportan desde @reelkit/react. Consulta la guía del estado en la URL y la API del core.
import { useOverlayUrlState, urlIndexKey, urlStableIdKey } from '@reelkit/react';
import { LightboxUrlOverlay } from '@reelkit/react-lightbox';
import { Link } from 'react-router-dom';
const photo = useOverlayUrlState({
param: 'photo',
...urlIndexKey(() => images.length),
});
// Opening is a link — the href is the open action. No open flag, no handler:
// the overlay reads the URL and opens itself.
{images.map((image, i) => (
<Link key={image.src} to={`?photo=${i}`}>
<img src={image.src} />
</Link>
))}
<LightboxUrlOverlay controller={photo} images={images} />El hook recibe un objeto de opciones y devuelve un UrlStateController (con set, index y value). Guárdalo para controlarlo por código: set es la escritura de bajo nivel que usa el overlay internamente (al cambiar de slide y con set(null) para cerrar). También maneja el overlay por código: set(index) lo abre, igual que navegar al parámetro. Aun así, es mejor abrirlo con un enlace: el href se puede compartir, se abre en una pestaña nueva y el botón de volver lo cierra, todo gratis y sin manejador.
Las opciones completas de useOverlayUrlState (param, adapter, codec, locator) están en la referencia de la API de React.
LightboxUrlOverlay solo recibe controller (obligatorio), un onClose opcional y todas las props visuales y de comportamiento de LightboxOverlay (images, ariaLabel, transitionFn, las render props y demás), pero no isOpen.
- Abrir cuesta una entrada en el historial. Pasar slides la sustituye, así que cien deslizamientos no añaden ninguna y volver una vez siempre sale de la galería. Volver cierra; no recorre las fotos.
- Un enlace compartido como
?photo=3abre la galería en ese slide. Al cerrar un enlace que llegó con la página, el parámetro se quita en el sitio en lugar de salir de tu web. - Volver solo cierra cuando abriste la galería desde dentro de la aplicación: el enlace añadió una entrada, así que volver regresa a la galería. Un enlace compartido abierto directamente en una pestaña nueva no tiene historial detrás, así que el botón de volver del navegador sale del sitio; el botón de cerrar o Escape quitan el parámetro en el sitio y te dejan en la galería. Los adaptadores de router incluidos confirman cuándo un enlace añadió una entrada en la misma página; un adaptador propio que no sepa cómo llegó la entrada también cierra en el sitio, lo que deja una copia de la página en el historial: volver una vez parece no hacer nada, pero nada se vuelve a abrir.
- Un parámetro que no nombra ningún slide (un marcador desfasado, un valor editado a mano) se quita de la URL en lugar de dejar la barra de direcciones apuntando a un slide que no se puede abrir.
En una aplicación con router, pasa un adaptador. Escribir directamente en el historial deja desfasada la ubicación del propio router, y su siguiente navegación pierde el parámetro.
import { useReactRouterUrlAdapter } from '@reelkit/react/react-router-url-adapter';
const adapter = useReactRouterUrlAdapter();
const photo = useOverlayUrlState({
param: 'photo',
adapter,
...urlIndexKey(() => images.length),
});
<LightboxUrlOverlay controller={photo} images={images} />Abrir es un enlace. Como el estado abierto vive en la URL, una miniatura es un enlace normal, sin manejador de clic, y el comportamiento propio del navegador sale gratis: abrir en una pestaña nueva, copiar la dirección, vista previa al pasar el ratón. En una aplicación con router usa el enlace del router para que todo siga en el cliente.
import { Link } from 'react-router-dom';
// The href is the open action — no onClick, no open flag.
{images.map((image, i) => (
<Link key={image.src} to={`?photo=${i}`}>
<img src={image.src} />
</Link>
))}
<LightboxUrlOverlay controller={photo} images={images} />Para enlaces compartibles, mejor una identidad estable. El índice es posicional, así que un ?photo=3 guardado abre otra imagen en cuanto la lista se reordena. urlStableIdKey usa como clave el id estable de cada elemento y recorre la lista actual; una sola llamada cubre el caso habitual.
const photo = useOverlayUrlState({
param: 'photo',
...urlStableIdKey({ items: () => images }),
});
<LightboxUrlOverlay controller={photo} images={images} />Pasa hashCodec: base64UrlCodec para codificar el id en base64url en la URL: es una ofuscación reversible, no un hash criptográfico.
Si usas otro campo como clave (un slug) o paginas un feed infinito con locateAsync, crea tú el codec y el locator:
const photo = useOverlayUrlState({
param: 'photo',
codec: { decode: (raw) => raw, encode: (id) => id },
locator: {
locate: (id) => images.findIndex((x) => x.slug === id),
identify: (index) => images[index].slug,
},
});
<LightboxUrlOverlay controller={photo} images={images} />Galerías infinitas o paginadas. El locate síncrono solo puede responder por las imágenes ya cargadas: un enlace compartido a la imagen 400 de un feed que ha cargado 20 no encuentra nada. locateAsync es la alternativa y solo se llama cuando locate falla.
Atajo
¿Usas el id del elemento como clave? Sáltate el codec y el locator hechos a mano y pasa locateAsync directamente a urlStableIdKey({ items, locateAsync }) (carga cuando no lo encuentra y después devuelve el índice). La versión más completa de abajo es para usar otro campo como clave o para tener el control total.
const photo = useOverlayUrlState({
param: 'photo',
codec: { decode: (raw) => raw, encode: (id) => id },
locator: {
locate: (id) => images.findIndex((x) => x.id === id),
identify: (index) => images[index].id,
locateAsync: async (id) => {
const loaded = await loadById(id); // or loadUntil(id) — fetch just that one, or page up to it
if (!loaded) return null; // exhausted — link names no image
setImages(loaded); // commit — the overlay renders from this state
return loaded.findIndex((x) => x.id === id); // wherever it landed
},
},
});
<LightboxUrlOverlay controller={photo} images={images} />- Cómo cargas los datos es cosa tuya: carga páginas seguidas hasta el objetivo, o carga solo esa imagen y añádela. La URL usa la identidad como clave, no la posición, así que
findIndexdevuelve el sitio donde acabe el elemento. - Mientras
locateAsyncestá pendiente, el lightbox sigue cerrado y el parámetro no se toca, así que el enlace directo sobrevive a la carga.nullo un rechazo quitan el parámetro. - Una respuesta que llega después de que la URL haya cambiado, después de cerrar o después de desmontar se descarta: una carga lenta no puede abrir un slide que nadie ha pedido.
- Mientras está pendiente no se renderiza nada; la página ya es dueña de ese estado de carga, así que renderiza tu propio esqueleto.
- No hay tiempo límite: el lightbox no puede saber lo larga que es la galería. Resuelve con
nullcuando se agote la paginación, o el overlay seguirá cerrado indefinidamente. - Lo que devuelva
locateAsyncmanda: es el índice de los datos que acaba de cargar y se usa tal cual, sin volver a leerimages.
Referencia de la API
Props de LightboxOverlay
LightboxOverlayProps
| Prop | Tipo | Por defecto | Descripción |
|---|---|---|---|
isOpen | boolean | obligatorio | Controla la visibilidad del lightbox. Para que el estado abierto lo controle la URL, usa el componente aparte LightboxUrlOverlay; mira el estado en la URL más arriba. |
images | LightboxItem[] | obligatorio | Array de imágenes que mostrar |
ariaLabel | string | 'Image gallery' | Etiqueta accesible de la región del diálogo; los lectores de pantalla la anuncian al abrirse el lightbox |
initialIndex | number | 0 | Índice de la imagen inicial |
transitionFn | TransitionTransformFn | slideTransition | Función de transición entre slides. Importa una incluida (slideTransition, flipTransition, lightboxFadeTransition, lightboxZoomTransition) o pasa una propia. Si se omite, se usa slideTransition. |
apiRef | MutableRefObject<ReelApi> | - | Ref para acceder a la API de Reel |
renderControls | (props: ControlsRenderProps) => ReactNode | - | Controles propios; sustituyen el botón de cerrar, el contador y el botón de pantalla completa por defecto |
renderNavigation | (props: NavigationRenderProps) => ReactNode | - | Navegación propia; sustituye las flechas de anterior y siguiente por defecto |
renderInfo | (props: InfoRenderProps) => ReactNode | - | Overlay de información propio; sustituye el degradado por defecto con el título y la descripción. Devuelve null para ocultarlo. |
renderSlide | (props: SlideRenderProps) => ReactNode | null | - | Renderizado propio del slide. Recibe { item, index, size, isActive, onReady, onWaiting, onError }. Devuelve null para usar el slide por defecto. |
renderLoading | (props: { item: LightboxItem; activeIndex: number }) => ReactNode | - | Indicador de carga propio; sustituye el spinner por defecto |
renderError | (props: { item: LightboxItem; activeIndex: number }) => ReactNode | - | Indicador de error propio; sustituye el icono de error por defecto |
Props de LightboxUrlOverlay
LightboxUrlOverlayProps
Acepta todas las props visuales y de comportamiento de arriba salvo isOpen, que se sustituye por controller. initialIndex se ignora aquí: la posición del controlador elige el slide, así que un valor pasado junto a él se sobrescribiría en cada apertura.
| Prop | Tipo | Por defecto | Descripción |
|---|---|---|---|
controller | UrlStateController | obligatorio | Controlador de useOverlayUrlState. Su posición decide si el overlay está abierto y qué slide muestra; el overlay escribe a través de él al cambiar de slide y al cerrar. |
Callbacks
| Prop | Tipo | Descripción |
|---|---|---|
onClose | () => void | Se llama al cerrar el lightbox. Obligatorio en LightboxOverlay (el estado abierto es tuyo, así que tienes que gestionar el cierre); opcional en LightboxUrlOverlay, donde la URL controla el cierre: pásalo solo para reaccionar después de cerrar. |
onSlideChange | (index: number) => void | Se llama después del cambio de slide |
Props de Reel (reenviadas)
Estas props se reenvían al componente Reel que hay debajo.
| Prop | Tipo | Por defecto | Descripción |
|---|---|---|---|
loop | boolean | false | Activa el bucle infinito |
enableNavKeys | boolean | true | Activa la navegación con teclado |
enableWheel | boolean | true | Activa la navegación con la rueda del ratón |
wheelDebounceMs | number | 200 | Duración del debounce de la rueda (ms) |
transitionDuration | number | 300 | Duración de la animación de transición (ms) |
swipeDistanceFactor | number | 0.12 | Umbral del deslizamiento (0-1) |
swipeToCloseDirection | 'up' | 'down' | 'up' | Dirección del gesto de deslizar para cerrar en móvil |
Tipos
LightboxItem
interface LightboxItem {
src: string;
type?: 'image' | 'video'; // defaults to 'image'
poster?: string; // thumbnail for video items
title?: string;
description?: string;
width?: number;
height?: number;
}ControlsRenderProps
interface ControlsRenderProps {
item: LightboxItem;
activeIndex: number;
count: number;
isFullscreen: boolean;
onClose: () => void;
onToggleFullscreen: () => void;
}NavigationRenderProps
interface NavigationRenderProps {
item: LightboxItem;
activeIndex: number;
count: number;
onPrev: () => void;
onNext: () => void;
}SlideRenderProps
interface SlideRenderProps {
item: LightboxItem;
index: number;
size: [number, number];
isActive: boolean;
onReady: () => void;
onWaiting: () => void;
onError: () => void;
}InfoRenderProps
interface InfoRenderProps {
item: LightboxItem;
index: number;
}Subcomponentes
Subcomponentes reutilizables para crear controles propios con renderControls.
CloseButton
Botón X de cerrar por defecto.
import { CloseButton } from '@reelkit/react-lightbox';
<CloseButton onClick={onClose} />Counter
Píldora con el contador de imágenes, por ejemplo "1 / 3".
import { Counter } from '@reelkit/react-lightbox';
<Counter currentIndex={activeIndex} count={count} />FullscreenButton
Botón para activar la pantalla completa (icono Maximize/Minimize).
import { FullscreenButton } from '@reelkit/react-lightbox';
<FullscreenButton isFullscreen={isFullscreen} onToggle={onToggleFullscreen} />SoundButton
Botón de silencio para los slides de vídeo (icono Volume2/VolumeX). Se incluye automáticamente en el renderControls de useVideoSlideRenderer. Para usarlo por separado dentro de controles propios, accede al estado del sonido con useSoundState.
import { SoundButton } from '@reelkit/react-lightbox';
import { useSoundState } from '@reelkit/react';
// Inside a component wrapped in SoundProvider:
function CustomControls({ onClose }) {
const soundState = useSoundState();
return (
<div>
<SoundButton
muted={soundState.muted.value}
onToggle={soundState.toggle}
/>
<button onClick={onClose}>Close</button>
</div>
);
}Hooks
useVideoSlideRenderer
Hook para el vídeo opcional. Devuelve renderSlide, renderControls y SoundProvider: envuelve el overlay con SoundProvider y pasa las funciones de renderizado.
import { useVideoSlideRenderer } from '@reelkit/react-lightbox';
const { renderSlide, renderControls, SoundProvider, hasVideo } =
useVideoSlideRenderer(items, isOpen);
// SoundProvider — wrap LightboxOverlay in this for mute/unmute support
// renderSlide — pass to LightboxOverlay's renderSlide prop
// renderControls — pass to LightboxOverlay's renderControls prop
// (includes Counter, FullscreenButton, SoundButton, CloseButton)
// hasVideo — true if items contain at least one video
// isOpen param — resets mute to true on close (enables autoplay on reopen)useFullscreen
Se ha movido
useFullscreen se eliminó de @reelkit/react-lightbox. Impórtalo desde @reelkit/react.
Hook para gestionar el estado de pantalla completa, compatible con todos los navegadores.
import { useRef } from 'react';
import { useFullscreen } from '@reelkit/react';
function CustomLightbox() {
const containerRef = useRef<HTMLDivElement>(null);
const [isFullscreen, requestFullscreen, exitFullscreen, toggleFullscreen] =
useFullscreen({ ref: containerRef });
return (
<div ref={containerRef}>
<button onClick={toggleFullscreen}>
{isFullscreen.value ? 'Exit Fullscreen' : 'Enter Fullscreen'}
</button>
</div>
);
}Transiciones
Pasa cualquier TransitionTransformFn con la prop transitionFn. Si importas solo la transición que usas, el bundler puede descartar el resto con tree-shaking. Si se omite, se usa slideTransition.
| Función | Origen | Descripción |
|---|---|---|
slideTransition | @reelkit/react-lightbox | Deslizamiento horizontal estándar (por defecto) |
lightboxFadeTransition | @reelkit/react-lightbox | Fundido cruzado entre imágenes |
flipTransition | @reelkit/react-lightbox | Efecto 3D de volteo de tarjeta |
lightboxZoomTransition | @reelkit/react-lightbox | Zoom de un tamaño menor al tamaño normal |
import {
LightboxOverlay,
lightboxFadeTransition,
} from '@reelkit/react-lightbox';
<LightboxOverlay
isOpen={isOpen}
images={images}
initialIndex={0}
onClose={handleClose}
transitionFn={lightboxFadeTransition}
/>Función de transición propia
Escribe tu propia TransitionTransformFn y pásala con transitionFn. La firma es la misma que la de las transiciones del slider del core.
import { LightboxOverlay } from '@reelkit/react-lightbox';
import type { TransitionTransformFn } from '@reelkit/react';
const customFade: TransitionTransformFn = (offset, size) => ({
transform: `translate3d(${offset * size[0]}px, 0, 0)`,
opacity: 1 - Math.min(Math.abs(offset), 1),
});
<LightboxOverlay
isOpen={isOpen}
images={images}
transitionFn={customFade}
onClose={() => setIsOpen(false)}
/>Clases CSS
Todos los elementos de la interfaz usan clases CSS normales (no CSS modules) a las que puedes apuntar con selectores más específicos en una hoja de estilos cargada después de @reelkit/react-lightbox/styles.css. Para cambiar colores, tamaños y z-index, es mejor usar las propiedades personalizadas de CSS de la sección Temas de más abajo.
| Clase | Componente | Descripción |
|---|---|---|
.rk-lightbox-overlay | Overlay | Contenedor raíz (fondo a pantalla completa) |
.rk-lightbox-spinner | Overlay | Spinner de carga por defecto |
.rk-lightbox-img-error | Overlay | Contenedor del estado de error (imagen o vídeo roto) |
.rk-lightbox-img-error-text | Overlay | Texto del estado de error |
.rk-lightbox-swipe-hint | Overlay | Pista de deslizamiento en móvil |
.rk-lightbox-controls-left | Controls | Contenedor de los controles de arriba a la izquierda |
.rk-lightbox-btn | Controls | Botones de control (pantalla completa, etc.) |
.rk-lightbox-close | Controls | Botón de cerrar |
.rk-lightbox-counter | Controls | Chip del contador de imágenes |
.rk-lightbox-nav | Navigation | Flechas de navegación (las dos) |
.rk-lightbox-nav-prev | Navigation | Flecha de anterior |
.rk-lightbox-nav-next | Navigation | Flecha de siguiente |
.rk-lightbox-info | Info | Contenedor del título y la descripción |
.rk-lightbox-title | Info | Título de la imagen |
.rk-lightbox-description | Info | Descripción de la imagen |
.rk-lightbox-slide | Slide | Contenedor del slide |
.rk-lightbox-img | Slide | Elemento de imagen |
.rk-lightbox-video-container | VideoSlide | Contenedor del slide de vídeo (opcional) |
.rk-lightbox-video-element | VideoSlide | Elemento de vídeo (opcional) |
.rk-lightbox-video-poster | VideoSlide | Imagen del póster del vídeo (opcional) |
Temas
Cada color, tamaño, z-index y transición vive en una propiedad personalizada de CSS. Sobrescribe una o varias en :root (o en cualquier ancestro del lightbox) para cambiar el tema sin tocar el código de los componentes.
| Token | Por defecto | Controla |
|---|---|---|
--rk-lightbox-overlay-bg | #000 | Color del fondo a pantalla completa |
--rk-lightbox-overlay-z | 9999 | z-index del overlay |
--rk-lightbox-top-shade-height | 80px | Altura del degradado superior |
--rk-lightbox-top-shade-bg | linear-gradient(rgba(0,0,0,0.6), transparent) | Color del degradado superior |
--rk-lightbox-edge-padding | 16px | Separación del borde de cerrar / navegación / controles de arriba a la izquierda |
--rk-lightbox-controls-gap | 12px | Espacio entre los controles de arriba a la izquierda |
--rk-lightbox-transition | 0.2s | Duración de la transición de los botones al pasar el ratón |
--rk-lightbox-blur | 8px | Radio del desenfoque de fondo de botones y chips |
--rk-lightbox-btn-bg | rgba(0, 0, 0, 0.5) | Fondo por defecto de los botones de cerrar, navegación y pequeños |
--rk-lightbox-btn-bg-hover | rgba(255, 255, 255, 0.2) | Fondo al pasar el ratón de los botones de cerrar, navegación y pequeños |
--rk-lightbox-btn-fg | #fff | Color del icono de los botones de cerrar, navegación y pequeños |
--rk-lightbox-btn-size | 36px | Tamaño de los botones pequeños (pantalla completa, etc.) |
--rk-lightbox-close-size | 40px | Tamaño del botón de cerrar |
--rk-lightbox-nav-size | 48px | Tamaño de las flechas de anterior y siguiente |
--rk-lightbox-nav-opacity | 0.7 | Opacidad en reposo de las flechas de anterior y siguiente |
--rk-lightbox-counter-fg | #fff | Color del texto del contador |
--rk-lightbox-counter-bg | rgba(0, 0, 0, 0.5) | Fondo del chip del contador |
--rk-lightbox-counter-size | 14px | Tamaño de letra del contador |
--rk-lightbox-counter-padding | 6px 12px | Relleno del chip del contador |
--rk-lightbox-counter-radius | 20px | border-radius del chip del contador |
--rk-lightbox-spinner-size | 28px | Ancho y alto del spinner por defecto |
--rk-lightbox-spinner-track | rgba(255, 255, 255, 0.2) | Color de la pista del spinner |
--rk-lightbox-spinner-fg | #fff | Color del indicador del spinner |
--rk-lightbox-spinner-duration | 0.8s | Duración de la rotación del spinner |
--rk-lightbox-error-fg | rgba(255, 255, 255, 0.4) | Color del icono y el texto de error |
--rk-lightbox-error-text-size | 13px | Tamaño de letra del mensaje de error |
--rk-lightbox-info-bg | linear-gradient(transparent, rgba(0,0,0,0.8)) | Degradado del fondo del pie |
--rk-lightbox-info-padding | 24px | Relleno interior del pie |
--rk-lightbox-title-size | 18px | Tamaño de letra del título |
--rk-lightbox-description-size | 14px | Tamaño de letra de la descripción |
--rk-lightbox-info-fg | #fff | Color del texto del pie |
--rk-lightbox-hint-fg | rgba(255, 255, 255, 0.5) | Color del texto de la pista de deslizamiento |
--rk-lightbox-hint-bg | rgba(0, 0, 0, 0.3) | Fondo del chip de la pista de deslizamiento |
--rk-lightbox-hint-duration | 3s | Duración total de la aparición y desaparición de la pista |
--rk-lightbox-video-bg | #000 | Fondo de las bandas detrás del <video> |
Pega el fragmento de abajo en una hoja de estilos cargada después de @reelkit/react-lightbox/styles.css.
/* Brand the lightbox */
:root {
--rk-lightbox-overlay-bg: #0f172a;
--rk-lightbox-btn-bg: rgba(99, 102, 241, 0.65);
--rk-lightbox-btn-bg-hover: rgba(168, 85, 247, 0.85);
--rk-lightbox-nav-size: 56px;
--rk-lightbox-counter-bg: rgba(99, 102, 241, 0.65);
--rk-lightbox-info-bg: linear-gradient(
transparent,
rgba(99, 102, 241, 0.55) 60%,
rgba(168, 85, 247, 0.85)
);
}Accesibilidad
La raíz del overlay es un diálogo modal (role="dialog", aria-modal="true"). Usa ariaLabel para cambiar lo que anuncia el lector de pantalla; por defecto es "Image gallery". Cada slide lleva role="group", aria-roledescription="slide" y aria-label="Image N of M".
El lightbox captura el foco al abrirse y lo devuelve al disparador al cerrarse. Tab y Mayús+Tab recorren los elementos enfocables de dentro; el foco que sale (un clic fuera, un foco por código) vuelve dentro. Está implementado con captureFocusForReturn y createFocusTrap de @reelkit/core.
Atajos de teclado
| Tecla | Acción |
|---|---|
ArrowLeft | Imagen anterior |
ArrowRight | Imagen siguiente |
Escape | Cierra el lightbox (o sale de la pantalla completa si está activa) |