Demos

Angular image gallery component

@lightgallery/angular is a native Angular image gallery: a standalone component with signal inputs and outputs, zoneless change detection and CDK overlay/a11y, in Angular Package Format with one entry point per feature. Animated thumbnails, pinch and double-tap zoom, captions, rotate, fullscreen and sharing are tree-shakable features. The full component API is in the Angular package docs.

Demo

Click any thumbnail. The Angular component renders the same markup and runs the same gallery logic, the shared headless core guarantees identical behavior across all four packages.

Install
npm install @lightgallery/angular @angular/cdk lightgallery

Peer ranges are @angular/core, @angular/common and @angular/cdk >=21 <23. There is no zone.js anywhere in the package, so it works with zoneless change detection. The CSS comes from the lightgallery package, add it to the styles array in angular.json or import it in your root stylesheet:

import 'lightgallery/css/lightgallery.css';
import 'lightgallery/css/lg-thumbnail.css';
import 'lightgallery/css/lg-zoom.css';
Thumbnail grid

Put lgGalleryItem on each trigger. Mount order is slide order, and clicking a trigger opens the lightbox on that slide:

import { Component } from '@angular/core';
import {
    LgGalleryComponent,
    LgGalleryItemDirective,
    type LgGalleryItem,
} from '@lightgallery/angular';
import { withThumbnail } from '@lightgallery/angular/plugins/thumbnail';
import { withZoom } from '@lightgallery/angular/plugins/zoom';

@Component({
    selector: 'app-gallery',
    imports: [LgGalleryComponent, LgGalleryItemDirective],
    template: `
        <lg-gallery [features]="features">
            @for (item of items; track item.src) {
                <a [href]="item.src" [lgGalleryItem]="item">
                    <img [src]="item.thumb" [alt]="item.alt" />
                </a>
            }
        </lg-gallery>
    `,
})
export class Gallery {
    features = [withThumbnail({ thumbWidth: 130 }), withZoom({ scale: 1.5 })];

    items: LgGalleryItem[] = [
        {
            src: 'img/1-1600.jpg',
            thumb: 'img/1-240.jpg',
            alt: 'Mountains',
            // enables the zoom-from-origin open animation
            lgSize: '1600-1067',
            caption: 'Mountains',
        },
        {
            src: 'img/2-1600.jpg',
            thumb: 'img/2-240.jpg',
            alt: 'Forest path',
            lgSize: '1600-2400',
            caption: 'Forest path',
        },
    ];
}
Settings, features and events

Core settings are same-named signal inputs ([mode], [speed], [loop], [captionPosition], …). Features come from the with<Name>() factories, each in its own entry point, and events are outputs without the on prefix:

<lg-gallery
    [features]="features"
    [speed]="400"
    (afterSlide)="onSlide($event)"
    (afterClose)="onClose()"
/>

Order matters for the slide wrappers: put withZoom() before withRotate().

Controlled and imperative

Drive the gallery from your own signals, or grab the component instance through its exported ref:

<button (click)="open.set(true)">Open gallery</button>
<button (click)="lg.openGallery(2)">Open at slide 3</button>

<lg-gallery
    #lg="lgGallery"
    [slides]="items"
    [open]="open()"
    (closed)="open.set(false)"
    [(index)]="index"
/>

The instance covers openGallery(index?), closeGallery(), goToSlide(i), nextSlide(), prevSlide() and refresh().

Templates instead of HTML strings

Captions, the counter and the navigation buttons are ng-template directives, lgCaption, lgCounter, lgPrevButton, lgNextButton, so the gallery chrome is your markup:

<lg-gallery [slides]="items">
    <ng-template lgCaption let-item let-index="index">
        <h4>{{ item?.caption }}</h4>
        <p>Slide {{ index + 1 }}</p>
    </ng-template>
</lg-gallery>

The directives are separate imports, add LgCaptionDirective (and its siblings) to the component’s imports alongside LgGalleryComponent.

SSR

Every entry point imports cleanly in bare Node and the overlay mounts through the CDK overlay after hydration, so Angular SSR works without a browser-only guard. Trigger markup server-renders, keeping the grid crawlable.

More in the Angular package docs, the full input surface, all 14 features plus the justified grid, and the accessibility behavior. See also the Angular video gallery demo.

Edit this page on GitHub