YouTube Playlist Carousel
The YouTube Playlist Carousel displays playlist videos in a carousel. Use server-side rendering: pass a videos array so all slides are rendered at build time with no API call.
Pre-rendered (no API call)
Pass a videos array to render all slides when the page loads. No loading state and no API call.
Server-side rendering markup
Pass a videos array so all slides are rendered at build time. The output includes data-videos-embedded="true" so the client does not call the API.
<div class="lta-youtube-playlist-carousel js-lta-youtube-playlist-carousel" data-videos-embedded="true">
<div class="lta-youtube-playlist-carousel__loading" style="display: none;" aria-hidden="true">
<p>Loading videos...</p>
</div>
<div class="lta-youtube-playlist-carousel__content">
<div class="lta-media-carousel lta-youtube-playlist-carousel__carousel" data-loop="false">
<div class="swiper">
<div class="swiper-wrapper">
<!-- One .swiper-slide per video (data-is-video="true"), each with figure.lta-video-embed, lite-video, figcaption -->
<div class="swiper-slide" data-is-video="true">
<figure class="lta-video-embed" data-video-name="Video title" data-video-url="https://www.youtube.com/watch?v=VIDEO_ID" data-video-date="...">
<lite-video videotype="youtube" videoid="VIDEO_ID" fallback-thumbnail="https://i.ytimg.com/vi/VIDEO_ID/maxresdefault.jpg"></lite-video>
<div class="lta-video-embed__caption-backdrop u-rounded-b"></div>
<figcaption class="lta-video-embed__caption u-rounded-b"><span>Video title | Monday, 20 September 2025</span></figcaption>
</figure>
</div>
<!-- ... more .swiper-slide -->
</div>
<div class="lta-media-carousel__controls">...</div>
</div>
</div>
</div>
<div class="lta-youtube-playlist-carousel__error" style="display: none;" aria-hidden="true">
<p class="u-text-error">Failed to load videos. Please try again later.</p>
</div>
</div>In 11ty, use the component with a videos array (e.g. from frontmatter or a data file) so this markup is generated at build time. No API key or runtime fetch is required.
Props
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
videos | array | Yes | - | Array of video objects for server-side rendering: videoId, title, thumbnail, publishedAt, videoUrl, description. All slides are rendered at build time (no API call). |
classes | string | No | - | Additional CSS classes to apply to the component wrapper |
Configuration
When using server-side rendering with the videos prop, all slides are output at build time. No API key or runtime request is required; the client only initialises the carousel on the existing markup.
With blockId (API fetch)
Pass a blockId as the payload. The client calls /api/youtube/block?blockId=...; the backend returns playlist videos for that block. The server outputs a shell with loading state; the client fetches and injects the slides.
Loading videos...
Server-side rendering markup (blockId)
When blockId is provided, the server renders this markup. The client reads data-block-id, calls GET /api/youtube/block?blockId=..., then injects slides and shows the content.
<div class="lta-youtube-playlist-carousel js-lta-youtube-playlist-carousel" data-block-id="youtube-playlist-bjk" data-cache-duration="10" data-block-endpoint="/api/youtube/block">
<div class="lta-youtube-playlist-carousel__loading u-text-center u-py-4">
<p>Loading videos...</p>
</div>
<div class="lta-youtube-playlist-carousel__content" style="display: none;">
<div class="lta-media-carousel lta-youtube-playlist-carousel__carousel" data-loop="false">
<div class="swiper">
<div class="swiper-wrapper"></div>
<div class="lta-media-carousel__controls">
<button class="lta-media-carousel__prev u-mr-2">
<svg class="lta-icon js-lta-text-input--btn-icon" width="2rem" height="2rem" style="color:currentColor;" fill="currentColor" alt="arrow-left-circle" aria-hidden="true">
<use xlink:href="/static/images/icons/lta-icons.svg#arrow-left-circle"></use>
</svg>
</button>
<div class="swiper-pagination u-hstack u-gap-1"></div>
<button class="lta-media-carousel__next u-ml-2">
<svg class="lta-icon js-lta-text-input--btn-icon" width="2rem" height="2rem" style="color:currentColor;" fill="currentColor" alt="arrow-right-circle" aria-hidden="true">
<use xlink:href="/static/images/icons/lta-icons.svg#arrow-right-circle"></use>
</svg>
</button>
</div>
</div>
</div>
</div>
<div class="lta-youtube-playlist-carousel__error" style="display: none;">
<p class="u-text-error">Failed to load videos. Please try again later.</p>
</div>
</div>Params (blockId mode)
| Param | Type | Required | Default | Description |
|---|---|---|---|---|
blockId | string | Yes | - | Block identifier. The client calls /api/youtube/block with this id; the backend returns playlist videos for the block. |
cacheDuration | string/number | No | - | Optional. Passed as data-cache-duration and to the block API (e.g. cache duration in minutes). |
blockEndpoint | string | No | /api/youtube/block | Block API URL. Passed as data-block-endpoint; the client uses it when fetching. Omit to use the default. |