Demos

Bootstrap video carousel with lightbox

Bootstrap is the most popular CSS Framework for developing responsive and mobile-first websites. Here is the demo adding lightbox gallery support for the Bootstrap video carousel.

Demo

HTML

<div
    id="bootstrap-video-carousel"
    class="carousel slide"
    data-bs-ride="carousel"
>
    <div class="carousel-indicators">
        <button
            type="button"
            data-bs-target="#bootstrap-video-carousel"
            data-bs-slide-to="0"
            class="active"
            aria-current="true"
            aria-label="Slide 1"
        ></button>
        <button
            type="button"
            data-bs-target="#bootstrap-video-carousel"
            data-bs-slide-to="1"
            aria-label="Slide 2"
        ></button>
    </div>
    <div class="carousel-inner">
        <div class="carousel-item active">
            <a
                data-lg-size="1280-720"
                class="lg-item"
                data-src="//vimeo.com/112836958"
                data-poster="..."
                data-sub-html="..."
            >
                <img
                    width="300"
                    height="100"
                    class="img-responsive"
                    src="/images/demo/vimeo-video-poster.jpg"
                />
            </a>
        </div>
        <div class="carousel-item">
            <a
                class="lg-item"
                data-lg-size="1280-720"
                data-src="https://private-sharing.wistia.com/medias/mwhrulrucj"
                data-poster="..."
                data-sub-html="..."
            >
                <img
                    width="300"
                    height="100"
                    class="img-responsive"
                    src="/images/demo/wistia-video-poster.jpeg"
                />
            </a>
        </div>
    </div>
    <button
        class="carousel-control-prev"
        type="button"
        data-bs-target="#bootstrap-video-carousel"
        data-bs-slide="prev"
    >
        <span class="carousel-control-prev-icon" aria-hidden="true"></span>
        <span class="visually-hidden">Previous</span>
    </button>
    <button
        class="carousel-control-next"
        type="button"
        data-bs-target="#bootstrap-video-carousel"
        data-bs-slide="next"
    >
        <span class="carousel-control-next-icon" aria-hidden="true"></span>
        <span class="visually-hidden">Next</span>
    </button>
</div>

JavaScript

const carouselEl = document.getElementById('bootstrap-video-carousel');

// The Bootstrap 5 carousel
new bootstrap.Carousel(carouselEl, {
    interval: 2000,
    wrap: false,
});

// One gallery over the carousel items, created once
lightGallery(carouselEl.querySelector('.carousel-inner'), {
    plugins: [lgVideo],
    selector: '.lg-item',
});
import { useEffect, useRef } from 'react';
import Carousel from 'bootstrap/js/dist/carousel';
import {
    LightGallery,
    LightGalleryItem,
    type GalleryItem,
} from '@lightgallery/react';
import Video from '@lightgallery/react/plugins/video';

// `src` is the address of the video page. `poster` is the image shown
// before the video plays, and the image on the carousel slide.
const items: GalleryItem[] = [
    {
        src: 'https://vimeo.com/112836958',
        poster: '/images/demo/vimeo-video-poster.jpg',
        alt: 'Nature',
        lgSize: '1280-720',
    },
    {
        src: 'https://private-sharing.wistia.com/medias/mwhrulrucj',
        poster: '/images/demo/wistia-video-poster.jpeg',
        alt: 'Thank You!',
        lgSize: '1280-720',
    },
];

const carouselRef = useRef<HTMLDivElement>(null);

// The Bootstrap 5 carousel
useEffect(() => {
    const carousel = new Carousel(carouselRef.current!, {
        interval: 2000,
        wrap: false,
        // Start cycling right away, as data-bs-ride="carousel" does
        ride: 'carousel',
    });
    return () => {
        // dispose() leaves the cycle timer running, so stop it first
        carousel.pause();
        carousel.dispose();
    };
}, []);

// One gallery over the carousel, every slide holds a video item
<LightGallery plugins={[Video]}>
    <div
        id="bootstrap-video-carousel"
        className="carousel slide"
        ref={carouselRef}
    >
        <div className="carousel-inner">
            {items.map((item, index) => (
                <div
                    key={item.poster}
                    className={
                        index === 0 ? 'carousel-item active' : 'carousel-item'
                    }
                >
                    <LightGalleryItem item={item}>
                        <img
                            src={item.poster}
                            className="d-block w-100"
                            alt={item.alt}
                        />
                    </LightGalleryItem>
                </div>
            ))}
        </div>
        {/* The indicators and the previous and next buttons, as in the
            Bootstrap markup */}
    </div>
</LightGallery>;
<script setup lang="ts">
import { onBeforeUnmount, onMounted, ref } from 'vue';
import Carousel from 'bootstrap/js/dist/carousel';
import { LightGallery, LgItem, type LgGalleryItem } from '@lightgallery/vue';
import Video from '@lightgallery/vue/plugins/video';

const plugins = [Video];

// `src` is the address of the video page. `poster` is the image shown
// before the video plays, and the image on the carousel slide.
const items: LgGalleryItem[] = [
    {
        src: 'https://vimeo.com/112836958',
        poster: '/images/demo/vimeo-video-poster.jpg',
        alt: 'Nature',
        lgSize: '1280-720',
    },
    {
        src: 'https://private-sharing.wistia.com/medias/mwhrulrucj',
        poster: '/images/demo/wistia-video-poster.jpeg',
        alt: 'Thank You!',
        lgSize: '1280-720',
    },
];

const carouselEl = ref<HTMLElement | null>(null);
let carousel: Carousel | undefined;

// The Bootstrap 5 carousel
onMounted(() => {
    carousel = new Carousel(carouselEl.value!, {
        interval: 2000,
        wrap: false,
        // Start cycling right away, as data-bs-ride="carousel" does
        ride: 'carousel',
    });
});
onBeforeUnmount(() => {
    // dispose() leaves the cycle timer running, so stop it first
    carousel?.pause();
    carousel?.dispose();
});
</script>

<template>
    <!-- One gallery over the carousel, every slide holds a video item -->
    <LightGallery :plugins="plugins">
        <div
            id="bootstrap-video-carousel"
            ref="carouselEl"
            class="carousel slide"
        >
            <div class="carousel-inner">
                <div
                    v-for="(item, index) of items"
                    :key="item.poster"
                    class="carousel-item"
                    :class="{ active: index === 0 }"
                >
                    <LgItem :item="item">
                        <img :src="item.poster" class="d-block w-100" :alt="item.alt" />
                    </LgItem>
                </div>
            </div>
            <!-- The indicators and the previous and next buttons, as in
                 the Bootstrap markup -->
        </div>
    </LightGallery>
</template>
import {
    afterNextRender,
    Component,
    DestroyRef,
    ElementRef,
    inject,
    viewChild,
} from '@angular/core';
import {
    LgGalleryComponent,
    LgGalleryItemDirective,
    type LgGalleryItem,
} from '@lightgallery/angular';
import { withVideo } from '@lightgallery/angular/plugins/video';
import Carousel from 'bootstrap/js/dist/carousel';

@Component({
    selector: 'app-gallery',
    imports: [LgGalleryComponent, LgGalleryItemDirective],
    template: `
        <!-- One gallery over the carousel, every slide holds a video item -->
        <lg-gallery [features]="features">
            <div #carousel id="bootstrap-video-carousel" class="carousel slide">
                <div class="carousel-inner">
                    @for (item of items; track item.poster) {
                        <div class="carousel-item" [class.active]="$first">
                            <a [lgGalleryItem]="item">
                                <img
                                    [src]="item.poster"
                                    class="d-block w-100"
                                    [alt]="item.alt"
                                />
                            </a>
                        </div>
                    }
                </div>
                <!-- The indicators and the previous and next buttons, as in
                     the Bootstrap markup -->
            </div>
        </lg-gallery>
    `,
})
export class Gallery {
    features = [withVideo()];

    // `src` is the address of the video page. `poster` is the image shown
    // before the video plays, and the image on the carousel slide.
    items: LgGalleryItem[] = [
        {
            src: 'https://vimeo.com/112836958',
            poster: '/images/demo/vimeo-video-poster.jpg',
            alt: 'Nature',
            lgSize: '1280-720',
        },
        {
            src: 'https://private-sharing.wistia.com/medias/mwhrulrucj',
            poster: '/images/demo/wistia-video-poster.jpeg',
            alt: 'Thank You!',
            lgSize: '1280-720',
        },
    ];

    carouselEl = viewChild.required<ElementRef<HTMLElement>>('carousel');

    constructor() {
        let carousel: Carousel | undefined;

        // The Bootstrap 5 carousel
        afterNextRender(() => {
            carousel = new Carousel(this.carouselEl().nativeElement, {
                interval: 2000,
                wrap: false,
                // Start cycling right away, as data-bs-ride="carousel" does
                ride: 'carousel',
            });
        });
        inject(DestroyRef).onDestroy(() => {
            // dispose() leaves the cycle timer running, so stop it first
            carousel?.pause();
            carousel?.dispose();
        });
    }
}

Edit this page on GitHub