Angular Lightbox

Lightbox im Vollbild für Bild- und Videogalerien in Angular, gebaut auf @reelkit/angular-lightbox.

Live-Demo ansehen →

Funktionen

Bilder und Video
Eingebaute Unterstützung für Video-Slides
Touch-Gesten
Wischen zum Navigieren
Wischen zum Schließen
Nach oben wischen zum Schließen
Tastaturnavigation
Pfeiltasten und Escape
Vollbild
Browserübergreifende API
Übergänge
Slide, Fade, Flip, Zoom-in
Vorladen
Benachbarte Bilder werden vorab geladen
Ton an/aus
Stummschalten pro Slide
Ladezustände
Spinner und eigener Slot
Fehlerbehandlung
Fehlersymbol und eigener Slot
Template-Slots
6 anpassbare Slot-Bereiche
OnPush
Angular-Signals und OnPush
URL-State
Teilbare Links mit Lesezeichen
Diashow
Optionales automatisches Weiterschalten mit Play/Pause
Download
Optionaler Button, der das aktive Element speichert

Installation

bash
npm install @reelkit/angular-lightbox @reelkit/angular lucide-angular

Registriere das Stylesheet einmal:

typescript
// Anywhere that runs at startup — main.ts, app.config.ts, a component file.
import '@reelkit/angular-lightbox/styles.css';

// Or, if you keep CSS out of TypeScript, from your global stylesheet:
//   @import '@reelkit/angular-lightbox/styles.css';
// Or register it in angular.json:
//   "styles": ["node_modules/@reelkit/angular-lightbox/styles.css"]
Symbole

Die Standard-Steuerelemente nutzen lucide-angular für die Symbole. Wenn du eine andere Symbolbibliothek bevorzugst, nutze die Template-Slots rkLightboxControls und rkLightboxNavigation, um deine eigenen einzusetzen.

Schnellstart

Importiere die Styles und die Standalone-Komponente RkLightboxOverlayComponent in das imports-Array deiner Komponente.

gallery.component.ts
import { Component } from '@angular/core';
import {
  RkLightboxOverlayComponent,
  type LightboxItem,
} from '@reelkit/angular-lightbox';
import '@reelkit/angular-lightbox/styles.css';

const images: LightboxItem[] = [
  {
    src: '/cdn/samples/images/image-01.jpg',
    title: 'Mountain River',
    description: 'A beautiful mountain river',
  },
  {
    src: '/cdn/samples/images/image-02.jpg',
    title: 'Snowy Peaks',
  },
  {
    src: '/cdn/samples/images/image-03.jpg',
    title: 'Misty Forest',
    description: 'Morning fog over the forest canopy',
  },
  {
    src: '/cdn/samples/images/image-04.jpg',
    title: 'Autumn Trail',
  },
  {
    src: '/cdn/samples/images/image-05.jpg',
    title: 'Ocean Cliff',
    description: 'Dramatic cliffs above the Pacific',
  },
  {
    src: '/cdn/samples/images/image-06.jpg',
    title: 'Desert Dunes',
  },
];

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [RkLightboxOverlayComponent],
  template: `
    <div style="display:grid;grid-template-columns:repeat(3,1fr);gap:8px">
      @for (img of images; track img.src; let i = $index) {
        <button (click)="openIndex = i" style="aspect-ratio:4/3;cursor:pointer">
          <img [src]="img.src" style="width:100%;height:100%;object-fit:cover" />
        </button>
      }
    </div>

    <rk-lightbox-overlay
      [isOpen]="openIndex !== null"
      [items]="images"
      [initialIndex]="openIndex ?? 0"
      (closed)="openIndex = null"
    />
  `,
})
export class AppComponent {
  images = images;
  openIndex: number | null = null;
}
Wo das Overlay gerendert wird

Anders als die Lightboxen für React und Vue, die ihr Overlay ans Ende von document.body verschieben, rendert rk-lightbox-overlay dort, wo du es platzierst, und bedeckt den Bildschirm mit position: fixed. Halte es von jedem Vorfahren mit transform, perspective, filter oder will-change: transform fern: Dieser Vorfahr wird zum Containing Block des Overlays, die Lightbox richtet ihre Größe dann nach ihm statt nach dem Viewport und wird von seinem overflow abgeschnitten. Ein Vorfahr mit eigenem Stacking Context begrenzt außerdem, wie weit --rk-lightbox-overlay-z die Lightbox anheben kann. Im Gegenzug erreichen --rk-lightbox-*-Tokens, die auf einem beliebigen Vorfahren gesetzt sind, die Lightbox.

Template-Slots

Mit Direktiven für Template-Slots passt du die Oberfläche des Overlays vollständig an, ohne die Komponente zu forken. Jeder Slot erhält ein streng typisiertes Kontextobjekt.

DirektiveKontexttypBeschreibung
[rkLightboxControls]LightboxControlsContextErsetzt die obere Steuerleiste (Schließen-Button, Zähler, Vollbild-Umschalter)
[rkLightboxNavigation]LightboxNavContextErsetzt die Navigationspfeile für zurück und weiter
[rkLightboxInfo]LightboxInfoContextErsetzt das untere Verlaufs-Overlay mit Titel und Beschreibung
[rkLightboxSlide]LightboxSlideContextErsetzt den Inhalt einzelner Slides (für Video-Slides erforderlich)
[rkLightboxLoading]LightboxLoadingContextEigene Ladeanzeige; die Klasse der Direktive ist RkLightboxLoadingDirective
[rkLightboxError]LightboxErrorContextEigene Fehleranzeige; die Klasse der Direktive ist RkLightboxErrorDirective
typescript
import {
  RkLightboxOverlayComponent,
  RkLightboxControlsDirective,
  RkLightboxNavigationDirective,
  RkLightboxInfoDirective,
  RkCloseButtonComponent,
  RkCounterComponent,
  RkFullscreenButtonComponent,
  type LightboxItem,
  type LightboxControlsContext,
  type LightboxNavContext,
} from '@reelkit/angular-lightbox';

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [
    RkLightboxOverlayComponent,
    RkLightboxControlsDirective,
    RkLightboxNavigationDirective,
    RkLightboxInfoDirective,
    RkCloseButtonComponent,
    RkCounterComponent,
    RkFullscreenButtonComponent,
  ],
  template: `
    <rk-lightbox-overlay [isOpen]="isOpen" [items]="images" (closed)="isOpen = false">

      <!-- Custom controls bar -->
      <ng-template rkLightboxControls
                   let-onClose="onClose"
                   let-activeIndex="activeIndex"
                   let-count="count"
                   let-isFullscreen="isFullscreen"
                   let-onToggleFullscreen="onToggleFullscreen">
        <div style="position:absolute;top:0;left:0;right:0;padding:12px;
                    display:flex;align-items:center;justify-content:space-between">
          <rk-close-button (clicked)="onClose()" />
          <rk-counter [currentIndex]="activeIndex + 1" [count]="count" />
          <rk-fullscreen-button
            [isFullscreen]="isFullscreen"
            (toggled)="onToggleFullscreen()" />
        </div>
      </ng-template>

      <!-- Custom navigation -->
      <ng-template rkLightboxNavigation
                   let-onPrev="onPrev"
                   let-onNext="onNext"
                   let-activeIndex="activeIndex"
                   let-count="count">
        <button (click)="onPrev()" [disabled]="activeIndex === 0">&#8592;</button>
        <button (click)="onNext()" [disabled]="activeIndex === count - 1">&#8594;</button>
      </ng-template>

      <!-- Custom info overlay -->
      <ng-template rkLightboxInfo let-item let-index="index">
        <div style="position:absolute;bottom:0;left:0;right:0;padding:16px;
                    background:linear-gradient(transparent,rgba(0,0,0,0.6))">
          <h3 style="color:#fff">{{ item.title }}</h3>
          <p style="color:rgba(255,255,255,0.7)">{{ item.description }}</p>
        </div>
      </ng-template>

    </rk-lightbox-overlay>
  `,
})
export class AppComponent {
  images: LightboxItem[] = [];
  isOpen = false;
}

Video-Unterstützung

Video-Slides aktivierst du über den Template-Slot rkLightboxSlide und die RkLightboxVideoSlideComponent. So landet der Videoplayer nicht im Bundle von Galerien, die nur Bilder brauchen.

Der eingebaute Ton-Button erscheint nur, wenn oberhalb von <rk-lightbox-overlay> ein SoundStateService bereitgestellt wird – erst diese geteilte Instanz lässt einen Umschalter das Video erreichen, da der Slide aus deinem Template gerendert wird. Ohne sie steuerst du das Element direkt mit setLightboxVideoMuted.

typescript
import {
  RkLightboxOverlayComponent,
  RkLightboxSlideDirective,
  RkLightboxVideoSlideComponent,
  type LightboxItem,
  type LightboxSlideContext,
} from '@reelkit/angular-lightbox';

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [
    RkLightboxOverlayComponent,
    RkLightboxSlideDirective,
    RkLightboxVideoSlideComponent,
  ],
  template: `
    <rk-lightbox-overlay [isOpen]="isOpen" [items]="items" (closed)="isOpen = false">
      <ng-template rkLightboxSlide
                   let-item
                   let-index="index"
                   let-size="size"
                   let-isActive="isActive"
                   let-autoAdvance="autoAdvance"
                   let-onReady="onReady"
                   let-onEnded="onEnded">
        @if (item.type === 'video') {
          <!-- With autoAdvance the video plays once and reports its end -->
          <rk-lightbox-video-slide
            [src]="item.src"
            [poster]="item.poster"
            [slideKey]="'lightbox-' + index"
            [size]="size"
            [isActive]="isActive"
            [loop]="!autoAdvance"
            [onReady]="onReady"
            [onEnded]="onEnded"
          />
        } @else {
          <img [src]="item.src"
               [style.width.px]="size[0]"
               [style.height.px]="size[1]"
               style="object-fit:contain" />
        }
      </ng-template>
    </rk-lightbox-overlay>
  `,
})
export class AppComponent {
  isOpen = false;
  items: LightboxItem[] = [
    { src: '/photo.jpg', title: 'Photo' },
    { src: '/clip.mp4', type: 'video', poster: '/clip-thumb.jpg', title: 'Video' },
  ];
}

Vollbild

Nutze fullscreenSignal, requestFullscreen und exitFullscreen aus @reelkit/angular, um den Vollbildzustand zu beobachten oder umzuschalten.

typescript
import { fullscreenSignal, requestFullscreen, exitFullscreen } from '@reelkit/angular';

@Component({ ... })
export class AppComponent {
  readonly isFullscreen = fullscreenSignal();

  toggle(container: HTMLElement): void {
    if (this.isFullscreen()) {
      exitFullscreen();
    } else {
      requestFullscreen(container);
    }
  }
}

URL-State

Live-Demo ansehen →

RkLightboxUrlOverlayComponent ist eine eigene Komponente, deren Öffnungszustand in der Adressleiste liegt. Baue einen Controller mit createOverlayUrlState und übergib ihn als [controller]: Die Galerie öffnet sich selbst, wenn der Parameter einen Slide benennt, und schließt sich, wenn er verschwindet. Links lassen sich teilen, und die Zurück-Taste schließt die Galerie, statt die Seite zu verlassen.

Eingebaute Schlüssel

Slides kannst du mit einem eingebauten Schlüssel adressieren – verteile urlIndexKey (nach Position) oder urlStableIdKey (nach einer stabilen id) in den Controller –, beide werden von @reelkit/angular re-exportiert. Siehe den Leitfaden zum URL-State und die Core-API.

typescript
import { RkLightboxUrlOverlayComponent } from '@reelkit/angular-lightbox';
import { createOverlayUrlState, urlIndexKey, urlStableIdKey } from '@reelkit/angular';

@Component({
  imports: [RkLightboxUrlOverlayComponent, RouterLink],
  template: `
    @for (image of images(); track image.src; let i = $index) {
      <a [routerLink]="[]" [queryParams]="{ photo: i }">
        <img [src]="image.src" alt="" />
      </a>
    }

    <rk-lightbox-url-overlay [controller]="photo" [items]="images()" />
  `,
})
export class GalleryComponent {
  protected readonly images = signal(photos);

  protected readonly photo = createOverlayUrlState({
    param: 'photo',
    ...urlIndexKey(() => this.images().length),
  });
}

Rufe es in einem Injection Context auf – in einem Feld-Initialisierer oder im Konstruktor. Es hängt sich sofort ein und gibt sich über DestroyRef wieder frei, sodass eine Komponente, die bei offener Galerie zerstört wird, keinen Listener zurücklässt. Alle Optionen findest du in der Angular-API-Referenz.

  • Das Öffnen legt einen Eintrag im Verlauf an. Das Blättern durch Slides ersetzt ihn, sodass N Schritte keine Einträge hinzufügen und ein Schritt zurück die Galerie immer verlässt.
  • Zurück schließt nur, wenn die Galerie innerhalb der App geöffnet wurde – der Link hat einen Eintrag angelegt. Ein geteilter Link, der direkt in einem neuen Tab geöffnet wird, hat keinen Verlauf hinter sich, daher verlässt die Zurück-Taste des Browsers die Seite; der ✕-Button oder Escape entfernt den Parameter an Ort und Stelle und bleibt auf der Seite.
  • Ein Parameter, der keinen Slide benennt – ein veraltetes Lesezeichen, ein von Hand geänderter Wert –, wird aus der URL entfernt, statt einen Slide zu behaupten, der sich nicht öffnen lässt.
  • Template-Slots funktionieren unverändert: Die URL-Komponente führt die sechs Slot-Abfragen selbst aus und reicht jedes Template an die Galerie weiter, sodass rkLightboxControls und seine Geschwister darin genauso sitzen wie in rk-lightbox-overlay.
  • In einer Anwendung mit Routing übergibst du einen Adapter, der auf Router aufbaut. Wer den Verlauf am Router vorbei schreibt, lässt dessen Location veralten, und seine nächste Navigation verwirft den Parameter.

In einer App mit Routing übergibst du einen Adapter. Wer den Verlauf am Router vorbei schreibt, lässt dessen Location veralten, und seine nächste Navigation verwirft den Parameter. Baue daher einen Adapter auf Router und übergib ihn als adapter:

typescript
import { createRouterUrlAdapter } from '@reelkit/angular/ng-router-url-adapter';

const adapter = createRouterUrlAdapter();

const photo = createOverlayUrlState({
  param: 'photo',
  adapter,
  ...urlIndexKey(() => this.images().length),
});

Stabile Links. Der Index ist positionsbasiert – ein gespeichertes ?photo=3 öffnet ein anderes Bild, sobald die Liste umsortiert wird. urlStableIdKey verwendet als Schlüssel die stabile id jedes Elements und durchsucht die aktuelle Liste – ein Aufruf deckt den üblichen Fall ab.

typescript
const photo = createOverlayUrlState({
  param: 'photo',
  ...urlStableIdKey({ items: () => this.images() }),
});

Übergib hashCodec: base64UrlCodec, um die id in der URL base64url-kodiert abzulegen – eine umkehrbare Verschleierung, kein kryptografischer Hash.

Willst du nach einem anderen Feld (einem slug) adressieren oder einen endlosen Feed mit locateAsync nachladen, baust du den codec (Format in der URL) und den locator (Suche) selbst:

typescript
const photo = createOverlayUrlState({
  param: 'photo',
  codec: { decode: (raw) => raw, encode: (id) => id },
  locator: {
    locate: (id) => this.images().findIndex((x) => x.id === id),
    identify: (index) => this.images()[index].id,
  },
});

Endlose oder seitenweise geladene Galerien. locate ist synchron und antwortet daher nur für bereits geladene Bilder – ein geteilter Link auf Bild 400 eines Feeds, der erst 20 geladen hat, findet nichts. locateAsync ist der Ausweg und wird nur aufgerufen, wenn locate nichts findet: Lade die nötigen Seiten und gib dann den Index zurück, den die Identität tatsächlich hat. Solange er aussteht, bleibt die Galerie geschlossen und der Parameter unangetastet, sodass der Deep Link das Laden übersteht; null oder eine Ablehnung entfernt den Parameter.

Abkürzung

Ist die id des Elements dein Schlüssel? Dann spar dir den selbst geschriebenen Codec und Locator – übergib locateAsync direkt an urlStableIdKey({ items, locateAsync }) (es lädt bei einem Fehltreffer nach und gibt dann den Index zurück). Die ausführlichere Variante unten ist für einen Schlüssel aus einem anderen Feld oder für volle Kontrolle gedacht.

typescript
const photo = createOverlayUrlState({
  param: 'photo',
  codec: { decode: (raw) => raw, encode: (id) => id },
  locator: {
    locate: (id) => this.images().findIndex((x) => x.id === id),
    identify: (index) => this.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 item
      this.images.set(loaded); // commit; the overlay renders from this
      return loaded.findIndex((x) => x.id === id); // wherever it landed
    },
  },
});

Automatisches Weiterschalten

Setze [autoAdvance]="true", damit die Galerie beim Öffnen als Diashow läuft. Standardmäßig ist es aus, sodass eine bestehende Lightbox wie bisher rendert und sich so verhält.

  • Bilder bleiben autoAdvanceInterval lang stehen (standardmäßig 5000 ms), gezählt ab dem Moment, in dem das Bild geladen ist – ein langsames Bild wird also nie übersprungen, bevor es jemand gesehen hat. Bei einem Bild, das nicht lädt, zählt die Zeit ab dem Fehler.
  • Videos laufen einmal durch, statt in einer Schleife zu spielen, und schalten weiter, wenn sie enden. Binde in einem rkLightboxSlide-Template [loop]="!autoAdvance" und [onEnded]="onEnded" an rk-lightbox-video-slide, wie unter Video-Unterstützung.
  • Es wartet, solange die Maus auf einem Steuerelement ruht (einem Button, einem Link oder der Bildunterschrift), während eines Wischens und solange die Seite verborgen ist, und macht dann dort weiter, wo es angehalten hat.
  • Wer von Hand blättert (Pfeile, Tasten, Mausrad, Wischen), startet das Intervall des neuen Slides bei null; die Diashow bleibt an.
  • Auf dem letzten Slide hält es an, außer loop ist gesetzt. Der Play/Pause-Button in den Steuerelementen zeigt den Zustand und lässt den Betrachter ihn umschalten.

Die Diashow läuft außerhalb der Angular-Zone, daher lösen ihre Animation Frames keine Change Detection aus. Ein eigenes rkLightboxControls-Template erhält isAutoAdvancing und, nur wenn autoAdvance an ist, onToggleAutoAdvance – rendere rk-play-pause-button, wenn es vorhanden ist. Das Timing selbst übernimmt createSlideshowController aus @reelkit/core; siehe den Leitfaden zu Autoplay und die Core-API.

typescript
import { Component } from '@angular/core';
import {
  RkCloseButtonComponent,
  RkLightboxControlsDirective,
  RkLightboxOverlayComponent,
  RkPlayPauseButtonComponent,
  type LightboxItem,
} from '@reelkit/angular-lightbox';

@Component({
  selector: 'app-gallery',
  imports: [
    RkLightboxOverlayComponent,
    RkLightboxControlsDirective,
    RkPlayPauseButtonComponent,
    RkCloseButtonComponent,
  ],
  template: `
    <rk-lightbox-overlay
      [isOpen]="isOpen"
      [items]="items"
      [autoAdvance]="true"
      [autoAdvanceInterval]="4000"
      (closed)="isOpen = false"
    >
      <!-- Optional: a custom bar shows the toggle only when its handler is there -->
      <ng-template rkLightboxControls let-ctx>
        @if (ctx.onToggleAutoAdvance) {
          <rk-play-pause-button
            [playing]="ctx.isAutoAdvancing"
            (toggled)="ctx.onToggleAutoAdvance()"
          />
        }
        <rk-close-button (clicked)="ctx.onClose()" />
      </ng-template>
    </rk-lightbox-overlay>
  `,
})
export class GalleryComponent {
  isOpen = false;
  items: LightboxItem[] = [{ src: '/beach.jpg' }, { src: '/forest.jpg' }];
}

Download

Setze [showDownload]="true", um den Steuerelementen einen Download-Button hinzuzufügen. Er speichert das aktive Element von seiner downloadUrl, ersatzweise von src, unter seinem downloadName, ersatzweise unter dem letzten Segment der URL.

Die Datei wird geladen und gespeichert, denn ein Browser ignoriert das Attribut download bei einem Link auf einen anderen Origin und würde die Datei stattdessen öffnen. Schlägt das Laden fehl – meist bei einem Server auf einem anderen Origin, der keine CORS-Header sendet –, öffnet sich die Datei in einem neuen Tab, wo der Betrachter sie trotzdem speichern kann. Liefere die Dateien mit Access-Control-Allow-Origin aus, damit ein Klick zum Speichern reicht. Der Button ist deaktiviert, während ein Download läuft.

Ein eigenes rkLightboxControls-Template erhält isDownloading und, nur wenn showDownload an ist, onDownload – rendere rk-download-button, wenn es vorhanden ist. Die Hilfsfunktion ist downloadFile aus @reelkit/core; siehe den Leitfaden zum Download.

typescript
import { Component } from '@angular/core';
import {
  RkCloseButtonComponent,
  RkDownloadButtonComponent,
  RkLightboxControlsDirective,
  RkLightboxOverlayComponent,
  type LightboxItem,
} from '@reelkit/angular-lightbox';

@Component({
  selector: 'app-gallery',
  imports: [
    RkLightboxOverlayComponent,
    RkLightboxControlsDirective,
    RkDownloadButtonComponent,
    RkCloseButtonComponent,
  ],
  template: `
    <rk-lightbox-overlay
      [isOpen]="isOpen"
      [items]="items"
      [showDownload]="true"
      (closed)="isOpen = false"
    >
      <!-- Optional: a custom bar shows the button only when its handler is there -->
      <ng-template rkLightboxControls let-ctx>
        @if (ctx.onDownload) {
          <rk-download-button
            [downloading]="ctx.isDownloading"
            (pressed)="ctx.onDownload()"
          />
        }
        <rk-close-button (clicked)="ctx.onClose()" />
      </ng-template>
    </rk-lightbox-overlay>
  `,
})
export class GalleryComponent {
  isOpen = false;
  items: LightboxItem[] = [
    {
      src: '/beach-1600.jpg',
      // Save the original rather than the resized preview
      downloadUrl: '/beach-original.jpg',
      downloadName: 'beach.jpg',
    },
  ];
}

Steuer-Buttons

KomponenteSelektorInputs / OutputsBeschreibung
RkPlayPauseButtonComponentrk-play-pause-button[playing], (toggled)Umschalter für die Diashow (Play/Pause-Symbol, aria-pressed während der Wiedergabe). Wird von den Standard-Steuerelementen mit autoAdvance angezeigt.
RkDownloadButtonComponentrk-download-button[downloading], (pressed)Download-Button, deaktiviert während downloading. Wird von den Standard-Steuerelementen mit showDownload angezeigt.
RkSoundButtonComponentrk-sound-button[muted], (toggled)Schalter für den Ton bei Video-Elementen. Wird von den Standard-Steuerelementen auf einem Video-Slide angezeigt; setze ihn in dein eigenes Template rkLightboxControls, um ihn zu behalten.

Inputs von RkLightboxUrlOverlayComponent

Nimmt jeden Input von rk-lightbox-overlay außer isOpen an, der durch einen Controller ersetzt wird. Die Outputs sind dieselben closed und slideChange; das Schließen steuert die URL, daher ist closed eine Benachrichtigung und nicht der Mechanismus.

InputTypStandardBeschreibung
controllerUrlStateControllerrequiredController aus createOverlayUrlState. Seine Position entscheidet, ob die Galerie offen ist und welchen Slide sie zeigt; die Komponente schreibt bei einem Slide-Wechsel und beim Schließen über ihn zurück.

Inputs von RkLightboxOverlayComponent

InputTypStandardBeschreibung
isOpenbooleanPflichtSteuert die Sichtbarkeit; bei false wird das Overlay aus dem DOM entfernt
itemsLightboxItem[]PflichtArray der Elemente der Lightbox (Bilder oder Videos)
initialIndexnumber0Nullbasierter Index des zuerst sichtbaren Elements
transitionFnTransitionTransformFnslideTransitionÜbergangsfunktion für Slides. Importiere einen eingebauten Übergang (slideTransition, flipTransition, lightboxFadeTransition, lightboxZoomTransition) oder übergib einen eigenen. Ohne Angabe wird slideTransition verwendet.
showInfobooleantrueOb das Info-Overlay mit Titel und Beschreibung gerendert wird
showControlsbooleantrueOb die obere Steuerleiste gerendert wird (Schließen, Zähler, Vollbild)
showNavigationbooleantrueOb die Navigationspfeile für zurück und weiter gerendert werden
transitionDurationnumber300Dauer der Slide-Animation in ms
swipeDistanceFactornumber0.12Mindestanteil der Wischstrecke (0–1), der einen Slide-Wechsel auslöst
swipeToCloseDirection'up' | 'down''up'Richtung der Wischgeste zum Schließen auf Mobilgeräten
loopbooleanfalseOb der Slider vom letzten Slide zurück zum ersten springt
enableNavKeysbooleantrueAktiviert die Navigation mit den Pfeiltasten
enableWheelbooleantrueAktiviert die Navigation mit dem Mausrad
wheelDebounceMsnumber200Debounce-Dauer für Mausrad-Events in ms
autoAdvancebooleanfalseSpielt die Galerie als Diashow ab. Siehe Automatisches Weiterschalten.
autoAdvanceIntervalnumber5000Wie lange jedes Bild während einer Diashow stehen bleibt, in ms, gezählt ab dem Laden
showDownloadbooleanfalseFügt einen Download-Button für das aktive Element hinzu. Siehe Download.
ariaLabelstring'Image gallery'Barrierefreie Beschriftung für den Dialogbereich

Die Slider-Inputs oben (transitionDuration, swipeDistanceFactor, loop, enableNavKeys, enableWheel, wheelDebounceMs) sind durch ReelProxyProps typisiert. Typisiere damit eine Wrapper-Komponente, die sie an die Lightbox weitergibt.

Outputs von RkLightboxOverlayComponent

OutputTypBeschreibung
closedEventEmitter<void>Wird ausgelöst, wenn der Nutzer die Lightbox schließt
slideChangeEventEmitter<number>Wird ausgelöst, wenn sich der Index des aktiven Slides ändert

Interface LightboxItem

FeldTypErforderlichBeschreibung
srcstringjaURL des Bildes oder Videos
type'image' | 'video'neinTyp des Elements. Standard ist 'image'
posterstringneinVorschaubild für Video-Elemente
titlestringneinTitel, der im Info-Overlay angezeigt wird
descriptionstringneinBeschreibung, die unter dem Titel angezeigt wird
widthnumberneinNatürliche Bildbreite in Pixeln
heightnumberneinNatürliche Bildhöhe in Pixeln
downloadUrlstringneinWas der Download-Button speichert. Standard ist src
downloadNamestringneinDateiname zum Speichern. Standard ist das letzte Segment des URL-Pfads

Kontexttypen der Template-Slots

TypFelder
LightboxControlsContext{ item, activeIndex, count, isFullscreen, isAutoAdvancing, isDownloading, onClose, onToggleFullscreen, onToggleAutoAdvance?, onDownload? }
LightboxNavContext{ item, onPrev, onNext, activeIndex, count }
LightboxInfoContext{ $implicit: LightboxItem, index }
LightboxSlideContext{ $implicit: LightboxItem, index, size: [number, number], isActive, autoAdvance, onReady, onWaiting, onError, onEnded }
LightboxLoadingContext{ $implicit: activeIndex, item } — was das Template rkLightboxLoading bekommt
LightboxErrorContext{ $implicit: activeIndex, item } — was das Template rkLightboxError bekommt

Übergänge

Übergib eine beliebige TransitionTransformFn über den Input transitionFn. Importierst du nur den Übergang, den du nutzt, kann der Bundler den Rest per Tree-Shaking entfernen. Ohne Angabe wird slideTransition verwendet.

FunktionAusBeschreibung
slideTransition@reelkit/angular-lightboxNormaler horizontaler Slide (Standard)
lightboxFadeTransition@reelkit/angular-lightboxÜberblendung zwischen Bildern
flipTransition@reelkit/angular-lightbox3D-Effekt einer umgedrehten Karte
lightboxZoomTransition@reelkit/angular-lightboxZoomt von kleiner auf normale Größe
typescript
import {
  RkLightboxOverlayComponent,
  lightboxFadeTransition,
} from '@reelkit/angular-lightbox';

@Component({
  imports: [RkLightboxOverlayComponent],
  template: `
    <rk-lightbox-overlay
      [isOpen]="isOpen"
      [items]="images"
      [transitionFn]="lightboxFadeTransition"
      (closed)="isOpen = false"
    />
  `,
})
export class GalleryComponent {
  protected readonly lightboxFadeTransition = lightboxFadeTransition;
}

Laden von Inhalten und Fehlerbehandlung

Mit dem Template-Slot rkLightboxSlide stehen im Kontext drei Lifecycle-Callbacks bereit, die den Ladezustand melden. Die Lightbox verfolgt den Zustand pro Slide und zeigt entsprechend einen Spinner oder ein Fehlersymbol. Ein Vorlader für Inhalte merkt sich defekte URLs, sodass ein erneuter Besuch eines fehlgeschlagenen Slides den Wiederholungsversuch überspringt.

Lifecycle-Callbacks

CallbackTypBeschreibung
onReady() => voidMeldet, dass der Inhalt des Slides erfolgreich geladen ist (zum Beispiel ein dekodiertes Bild)
onWaiting() => voidMeldet, dass der Inhalt des Slides lädt oder puffert (zeigt den Spinner)
onError() => voidMeldet, dass der Inhalt des Slides nicht geladen werden konnte (zeigt das Fehlersymbol)

Callbacks in rkLightboxSlide verbinden

html
<rk-lightbox-overlay [isOpen]="isOpen" [items]="items" (closed)="isOpen = false">
  <ng-template rkLightboxSlide
               let-item
               let-size="size"
               let-isActive="isActive"
               let-onReady="onReady"
               let-onWaiting="onWaiting"
               let-onError="onError">
    @if (item.type === 'video') {
      <rk-lightbox-video-slide
        [item]="item"
        [size]="size"
        [isActive]="isActive"
      />
    } @else {
      <img [src]="item.src"
           [style.width.px]="size[0]"
           [style.height.px]="size[1]"
           style="object-fit:contain"
           (load)="onReady()"
           (error)="onError()" />
    }
  </ng-template>
</rk-lightbox-overlay>

Eigenes Lade-Template

Mit der Direktive rkLightboxLoading ersetzt du den Standard-Spinner.

html
<rk-lightbox-overlay [isOpen]="isOpen" [items]="items" (closed)="isOpen = false">
  <ng-template rkLightboxLoading let-index let-item="item">
    <div style="display:flex;flex-direction:column;align-items:center;color:#fff">
      <span>Loading image {{ index + 1 }}...</span>
      <span style="opacity:0.6">{{ item.title }}</span>
    </div>
  </ng-template>
</rk-lightbox-overlay>

Eigenes Fehler-Template

Mit der Direktive rkLightboxError ersetzt du das Standard-Fehlersymbol.

html
<rk-lightbox-overlay [isOpen]="isOpen" [items]="items" (closed)="isOpen = false">
  <ng-template rkLightboxError let-index let-item="item">
    <div style="display:flex;flex-direction:column;align-items:center;color:#ef4444">
      <span>Failed to load</span>
      <span style="opacity:0.6">{{ item.title ?? item.src }}</span>
    </div>
  </ng-template>
</rk-lightbox-overlay>

CSS-Klassen

Alle CSS-Klassen sind einfach (nicht gekapselt), sodass du sie mit spezifischeren Selektoren in einem Stylesheet ansprechen kannst, das nach @reelkit/angular-lightbox/styles.css geladen wird. Für Änderungen an Farbe, Größe und z-index nutzt du besser die CSS Custom Properties, die unten im Abschnitt Theming beschrieben sind.

KlasseKomponenteBeschreibung
.rk-lightbox-overlayOverlayRoot-Container (Vollbild-Hintergrund)
.rk-lightbox-top-shadeOverlayOberer Verlauf hinter den Steuerelementen
.rk-lightbox-spinnerOverlayStandard-Ladespinner
.rk-lightbox-img-errorOverlayContainer für den Fehlerzustand (defektes Bild)
.rk-lightbox-img-error-textOverlayTextbeschriftung des Fehlerzustands
.rk-lightbox-swipe-hintOverlayWischhinweis auf Mobilgeräten
.rk-lightbox-emptyOverlayText für den leeren Zustand
.rk-lightbox-controls-leftControlsContainer für die Steuerelemente oben links
.rk-lightbox-btnControlsSteuer-Button (Vollbild und andere)
.rk-lightbox-play-pauseControlsPlay/Pause-Button der Diashow (mit .rk-lightbox-btn)
.rk-lightbox-downloadControlsDownload-Button (mit .rk-lightbox-btn)
.rk-lightbox-closeControlsSchließen-Button
.rk-lightbox-counterControlsChip mit dem Bildzähler
.rk-lightbox-navNavigationNavigationspfeil (zurück und weiter)
.rk-lightbox-nav-prevNavigationPfeil zurück
.rk-lightbox-nav-nextNavigationPfeil weiter
.rk-lightbox-infoInfoContainer für Titel und Beschreibung
.rk-lightbox-titleInfoBildtitel
.rk-lightbox-descriptionInfoBildbeschreibung
.rk-lightbox-slideSlideSlide-Container
.rk-lightbox-imgSlideBildelement
.rk-lightbox-video-containerVideoSlideContainer für Video-Slides (optional)
.rk-lightbox-video-elementVideoSlideVideoelement (optional)
.rk-lightbox-video-posterVideoSlidePosterbild des Videos (optional)
.rk-lightbox-video-errorVideoSlideContainer für den Fehlerzustand des Videos

Theming

Jede Farbe, Größe, jeder z-index und jeder Übergang liegt in einer CSS Custom Property. Überschreibe eine oder mehrere auf :root (oder einem beliebigen Vorfahren der Lightbox), um das Aussehen zu ändern, ohne den Quellcode der Komponente anzufassen. Die Tokens entsprechen denen der Lightbox für React, sodass sich Überschreibungen zwischen den Bindings übertragen lassen.

TokenStandardSteuert
--rk-lightbox-overlay-bg#000Farbe des Vollbild-Hintergrunds
--rk-lightbox-overlay-z9999z-index des Overlays
--rk-lightbox-top-shade-height80pxHöhe des oberen Verlaufs
--rk-lightbox-top-shade-bglinear-gradient(rgba(0,0,0,0.6), transparent)Farbe des oberen Verlaufs
--rk-lightbox-edge-padding16pxRandabstand für Schließen, Navigation und Steuerelemente oben links
--rk-lightbox-controls-gap12pxAbstand zwischen den Steuerelementen oben links
--rk-lightbox-transition0.2sDauer des Hover-Übergangs der Buttons
--rk-lightbox-blur8pxRadius der Hintergrundunschärfe für Buttons und Chips
--rk-lightbox-btn-bgrgba(0, 0, 0, 0.5)Standardhintergrund für Schließen, Navigation und kleine Buttons
--rk-lightbox-btn-bg-hoverrgba(255, 255, 255, 0.2)Hover-Hintergrund für Schließen, Navigation und kleine Buttons
--rk-lightbox-btn-fg#fffSymbolfarbe für Schließen, Navigation und kleine Buttons
--rk-lightbox-btn-size36pxGröße der kleinen Buttons (Vollbild-Umschalter und andere)
--rk-lightbox-btn-disabled-opacity0.5Deckkraft eines deaktivierten kleinen Buttons (während eines Downloads)
--rk-lightbox-close-size40pxGröße des Schließen-Buttons
--rk-lightbox-nav-size48pxGröße der Pfeile für zurück und weiter
--rk-lightbox-nav-opacity0.7Deckkraft der Pfeile im Ruhezustand
--rk-lightbox-counter-fg#fffTextfarbe des Zählers
--rk-lightbox-counter-bgrgba(0, 0, 0, 0.5)Hintergrund des Zähler-Chips
--rk-lightbox-counter-size14pxSchriftgröße des Zählers
--rk-lightbox-counter-padding6px 12pxInnenabstand des Zähler-Chips
--rk-lightbox-counter-radius20pxEckenradius des Zähler-Chips
--rk-lightbox-spinner-size28pxBreite und Höhe des Standard-Spinners
--rk-lightbox-spinner-duration0.8sRotationsdauer des Spinners
--rk-lightbox-error-fgrgba(255, 255, 255, 0.4)Farbe von Fehlersymbol und Text
--rk-lightbox-info-bglinear-gradient(transparent, rgba(0,0,0,0.8))Verlauf hinter der Bildunterschrift
--rk-lightbox-info-padding24pxInnenabstand der Bildunterschrift
--rk-lightbox-title-size18pxSchriftgröße des Titels
--rk-lightbox-description-size14pxSchriftgröße der Beschreibung
--rk-lightbox-hint-fgrgba(255, 255, 255, 0.5)Textfarbe des Wischhinweises
--rk-lightbox-hint-bgrgba(0, 0, 0, 0.3)Hintergrund des Chips mit dem Wischhinweis
--rk-lightbox-video-bg#000Hintergrund der Letterbox hinter <video>

Füge das folgende Snippet in ein Stylesheet ein, das nach @reelkit/angular-lightbox/styles.css geladen wird.

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)
  );
}

Barrierefreiheit

Das Root-Element des Overlays ist ein modaler Dialog (role="dialog", aria-modal="true"). Setze den Input ariaLabel, um die Ansage für Screenreader zu ändern; standardmäßig lautet sie „Image gallery“. Jeder Slide trägt role="group", aria-roledescription="slide" und ein aria-label, das sich aus dem Bildtitel und der Position ergibt.

Die Lightbox fängt beim Öffnen den Fokus ein und gibt ihn beim Schließen an den Auslöser zurück. Tab und Shift+Tab wechseln zwischen den fokussierbaren Elementen darin; Fokus, der entkommt (Klick außerhalb, programmatischer Fokus), wird zurückgeholt. Umgesetzt mit captureFocusForReturn und createFocusTrap aus @reelkit/core.

Tastenkürzel

TasteAktion
ArrowLeftVorheriges Bild
ArrowRightNächstes Bild
EscapeSchließt die Lightbox (oder beendet den Vollbildmodus, falls aktiv)