diff --git a/js/privacy/eclipsefdn.videos.js b/js/privacy/eclipsefdn.videos.js
index 34b1981ccfc1ed66e0132f4488cebf7e5c510733..c577a3421acf1c46f0bd3b1e98c8ade256b6dad8 100644
--- a/js/privacy/eclipsefdn.videos.js
+++ b/js/privacy/eclipsefdn.videos.js
@@ -11,6 +11,35 @@
  *
  * SPDX-License-Identifier: EPL-2.0
  */
+
+/**
+ * Checks if a given YouTube ID is likely a playlist ID.
+ * This determination is based on common prefixes (PL, UU, FL, RD) and length patterns,
+ * distinguishing them from typical 11-character video IDs.
+ * Assumes the input 'id' is the cleaned ID string, without URL parameters.
+ *
+ * @param {string} id The YouTube ID string to check.
+ * @returns {boolean} True if the ID is likely a playlist ID, false otherwise.
+ */
+export const isPlaylistId = (id) => {
+  if (typeof id !== 'string' || id.trim() === '') {
+    return false; // Not a valid ID format
+  }
+
+  if (
+    (id.startsWith('PL') && id.length > 11) ||
+    (id.startsWith('UU') && id.length === 24) ||
+    (id.startsWith('FL') && id.length === 24) ||
+    (id.startsWith('RD') && id.length > 11)
+  ) {
+    return true;
+  }
+
+  // If none of the above conditions for playlists are met, it's not considered a playlist.
+  // This includes typical 11-character video IDs (e.g., "PL3DQBsESiQ" or "dQw4w9WgXcQ").
+  return false;
+}
+
 const eclipseFdnVideos = (function (window, document) {
   (function (root, factory) {
     if (typeof define === 'function' && define.amd) {
@@ -106,7 +135,7 @@ const eclipseFdnVideos = (function (window, document) {
         .then(response => response.json())
         .then(data => data.thumbnail_url);
 
-    const isYoutubeLink = (link) => /^(https?:)?(\/\/)?(www\.)?(youtube\.com|youtu\.be)\//.test(link)
+    const isYoutubeLink = link => /^(https?:)?(\/\/)?(www\.)?(youtube\.com|youtu\.be)\//.test(link);
 
     /**
      * Adds a video thumbnail to the given item element.
@@ -140,7 +169,31 @@ const eclipseFdnVideos = (function (window, document) {
       }
     };
 
-    const buildLinkFromId = (id) => id.startsWith('PL') ? `//www.youtube.com/embed/playlist?list=${id}` : `//www.youtube.com/embed/${id}`;
+    /**
+     * If the element is an anchor tag, it checks if it has href and replaces the href with the link.
+     * If the element is not a link, it wraps the item with an anchor tag.
+     *
+     * @param {string} link
+     * @param {HTMLElement} item
+     * @returns void
+     */
+    const wrapWithLink = (item, link) => {
+      const isLink = item.tagName === 'A';
+      const anchor = isLink ? item : document.createElement('a');
+
+      anchor.setAttribute('href', link);
+      anchor.setAttribute('target', '_blank');
+
+      if (!isLink) {
+        anchor.appendChild(item.cloneNode(true));
+        item.replaceWith(anchor);
+      }
+    };
+
+    const buildLinkFromId = id =>
+      isPlaylistId(id)
+        ? `//www.youtube.com/embed/playlist?list=${id}`
+        : `//www.youtube.com/embed/${id}`;
 
     /**
      * Processes video elements in the document, replacing them with iframes or setting thumbnails.
@@ -182,6 +235,7 @@ const eclipseFdnVideos = (function (window, document) {
           item.replaceWith(createVideoContainer(link, resolution));
         } else {
           addVideoThumbnail(item, link);
+          wrapWithLink(item, link);
         }
       });
     };
diff --git a/js/solstice/eclipsefdn.paginated-video-list.js b/js/solstice/eclipsefdn.paginated-video-list.js
new file mode 100644
index 0000000000000000000000000000000000000000..c29cad76c216fa8b42ffa3858cfd1cdfcb23cbc9
--- /dev/null
+++ b/js/solstice/eclipsefdn.paginated-video-list.js
@@ -0,0 +1,190 @@
+/**
+ * Copyright (c) Eclipse Foundation
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+
+import defaultTemplate from './templates/paginated-video-list.mustache';
+import renderTemplate from './templates/render-template';
+import { isPlaylistId, renderVideos } from '../privacy/eclipsefdn.videos';
+
+const defaultOptions = {
+  count: 5,
+  filterable: true,
+};
+
+/**
+ * Initializes a paginated video list with category filtering capabilities.
+ * @param {HTMLElement} element - The container element for the video list.
+ * @description This function creates a paginated list of video items with category filtering.
+ * @remarks This function expects to find a list of video items within the provided element. @see {@link stories/widgets/eclipsefdn-paginated-video-list.stories.ts}
+ */
+const initializePaginatedVideoList = element => {
+  const { count: datasetcount, filterable: datasetFilterable } = element?.dataset;
+
+  const options = {
+    ...defaultOptions,
+    ...{
+      count: datasetcount && parseInt(datasetcount),
+      filterable: datasetFilterable && datasetFilterable === 'true',
+    },
+  };
+
+  // Parse the minimal markup into an internal data structure
+  const providedVideoItems = Array.from(element.querySelectorAll('.video-item')).map(item => ({
+    id: item.dataset.id,
+    title: item.dataset.title,
+    date: item.dataset.date,
+    description: item.dataset.description,
+    category: item.dataset.category,
+    url: isPlaylistId(item.dataset.id)
+      ? `https://www.youtube.com/playlist?list=${item.dataset.id}`
+      : `https://www.youtube.com/watch?v=${item.dataset.id}`,
+  }));
+
+  // Force uniquety of categories by using a Set
+  const categories = [...new Set(providedVideoItems.map(item => item.category))];
+
+  const state = {
+    currentPage: 1,
+    filteredItems: providedVideoItems,
+    selectedCategory: 'none',
+  };
+
+  /**
+   * Calculates pagination information based on the current state and options
+   * @returns {Object} Pagination object containing:
+   *   @property {Array<Object>} pages - Array of page objects with number and active status
+   *   @property {boolean} showPrevious - Whether to show previous page button
+   *   @property {boolean} showNext - Whether to show next page button
+   *   @property {number} currentPage - Current active page number
+   *   @property {boolean} hasMultiplePages - Whether there are multiple pages
+   */
+  const computePagination = () => {
+    const pageCount = Math.ceil(state.filteredItems.length / options.count);
+    const isFirstPage = state.currentPage === 1;
+    const isLastPage = state.currentPage === pageCount;
+
+    const pages = Array.from({ length: pageCount }, (_, i) => ({
+      number: i + 1,
+      active: i + 1 === state.currentPage,
+    }));
+
+    return {
+      pages,
+      showPrevious: !isFirstPage,
+      showNext: !isLastPage,
+      currentPage: state.currentPage,
+      showPagination: pages.length > 1,
+    };
+  };
+
+  /**
+   * Calculates and returns a subset of filtered items based on the current page and items per page.
+   * @returns {Array} A slice of filteredItems corresponding to the current page.
+   */
+  const computePageItems = () => {
+    const start = (state.currentPage - 1) * options.count;
+    const end = start + options.count;
+
+    return state.filteredItems.slice(start, end);
+  };
+
+  /**
+   * Maps through the categories array and returns an array of objects containing
+   * the category value, label, and selected state.
+   * @returns {Array<{value: string, label: string, selected: boolean}>} Array of category objects
+   */
+  const computeCategories = () =>
+    categories.map(cat => ({
+      value: cat,
+      label: cat,
+      selected: cat === state.selectedCategory,
+    }));
+
+  /**
+   * Updates the display of the paginated video list by rendering the template with current state
+   * and attaching necessary event listeners.
+   * @async
+   * @returns {Promise<void>} A promise that resolves when the display has been updated
+   */
+  const updateDisplay = async () => {
+    await renderTemplate({
+      element,
+      templates: { default: defaultTemplate },
+      templateId: 'default',
+      data: {
+        items: computePageItems(),
+        categories: computeCategories(),
+        noCategory: state.selectedCategory === 'none',
+        showCategories: options.filterable && categories.length > 1,
+        pagination: computePagination(),
+      },
+    });
+
+    attachEventListeners();
+
+    // Re-render the videos given that the template has been updated asynchronously
+    renderVideos();
+  };
+
+  /**
+   * Updates the current category filter and refreshes the video list display
+   * @param {string} category - The category to filter by. Use 'none' to show all videos
+   */
+  const triggerCategoryUpdate = category => {
+    state.selectedCategory = category;
+    state.filteredItems =
+      category === 'none'
+        ? providedVideoItems
+        : providedVideoItems.filter(item => item.category === category);
+    state.currentPage = 1;
+    updateDisplay();
+  };
+
+  const attachEventListeners = () => {
+    const categorySelect = element.querySelector('.video-categories');
+    const paginationEl = element.querySelector('.pagination-videos');
+
+    if (categorySelect) {
+      categorySelect.addEventListener('change', e => {
+        triggerCategoryUpdate(e.target.value);
+      });
+    }
+
+    if (paginationEl) {
+      paginationEl.addEventListener('click', e => {
+        e.preventDefault();
+        const target = e.target.closest('a');
+        if (!target) return;
+
+        if (target.getAttribute('aria-label') === 'Previous') {
+          state.currentPage--;
+        } else if (target.getAttribute('aria-label') === 'Next') {
+          state.currentPage++;
+        } else {
+          state.currentPage = parseInt(target.textContent);
+        }
+
+        updateDisplay();
+      });
+    }
+  };
+
+  updateDisplay();
+};
+
+const render = () => {
+  const allPaginatedVideoLists = document.querySelectorAll('.eclipsefdn-paginated-video-list');
+  Array.from(allPaginatedVideoLists).forEach(initializePaginatedVideoList);
+};
+
+const eclipsefdnPaginatedVideoList = {
+  render,
+};
+
+export default eclipsefdnPaginatedVideoList;
diff --git a/js/solstice/index.js b/js/solstice/index.js
index 61a9bfb4364a1f1c813e464d599358272a539ef9..a5e5e84b46f3a561b0f3a74543bdc8d89f5d7d4e 100644
--- a/js/solstice/index.js
+++ b/js/solstice/index.js
@@ -35,6 +35,7 @@ import eclipsefdnSolsticeSlider from './eclipsefdn.solstice-slider';
 import eclipsefdnVideoList from './eclipsefdn.video-list.js';
 import eclipsefdnWeightedCollaborations from './eclipsefdn.weighted-collaborations';
 import eclipsefdnWorkingGroupsList from './eclipsefdn.wgs-list.js'
+import eclipsefdnPaginatedVideoList from './eclipsefdn.paginated-video-list.js';
 
 
 document.addEventListener('DOMContentLoaded', () => {
@@ -49,6 +50,7 @@ document.addEventListener('DOMContentLoaded', () => {
   eclipsefdnPromotion.render();
   eclipsefdnSolsticeSlider.render();
   eclipsefdnVideoList.render();
+  eclipsefdnPaginatedVideoList.render();
   eclipsefdnWeightedCollaborations.render();
   eclipsefdnWorkingGroupsList.render();
 });
diff --git a/js/solstice/templates/paginated-video-list.mustache b/js/solstice/templates/paginated-video-list.mustache
new file mode 100644
index 0000000000000000000000000000000000000000..7b3b016f69cf93b4cfde0cfa9169aff1991bca6a
--- /dev/null
+++ b/js/solstice/templates/paginated-video-list.mustache
@@ -0,0 +1,50 @@
+{{#showCategories}}
+<div class="form-group row">
+    <div class="col-sm-6">
+        <select class="search form-control video-categories" aria-label="Video category filter">
+            <option value="none" {{#noCategory}}selected{{/noCategory}}>Choose a category</option>
+            {{#categories}}
+            <option value="{{value}}" {{#selected}}selected{{/selected}}>{{label}}</option>
+            {{/categories}}
+        </select>
+    </div>
+</div>
+{{/showCategories}}
+
+<ul class="list list-unstyled video-items">
+    {{#items}}
+    <li class="row featured-section-resources-video-item margin-bottom-60">
+        <div class="col-sm-11">
+            <a class="eclipsefdn-video" data-id="{{id}}"></a>
+        </div>
+        <div class="col-sm-11 col-sm-offset-1 padding-top-30 padding-bottom-30">
+            <p class="featured-section-resources-video-date text-secondary">{{date}}</p>
+            <h2 class="h3 featured-section-resources-video-heading big-text">
+                <a href="{{url}}" class="link-unstyled" target="_blank">{{title}}</a>
+            </h2>
+            <p class="featured-section-resources-video-description margin-bottom-20">{{description}}</p>
+            <p><a class="btn btn-primary" href="{{url}}" target="_blank">Watch on Youtube</a></p>
+        </div>
+    </li>
+    {{/items}}
+</ul>
+
+{{#pagination.showPagination}}
+<div class="text-center">
+    <ul class="pagination pagination-videos text-center">
+        {{#pagination.showPrevious}}
+        <li><a href="#" aria-label="Previous"><i class="fa-solid fa-chevron-left" aria-hidden></i></a></li>
+        {{/pagination.showPrevious}}
+        
+        {{#pagination.pages}}
+        <li {{#active}}class="active"{{/active}}>
+            <a href="#">{{number}}</a>
+        </li>
+        {{/pagination.pages}}
+        
+        {{#pagination.showNext}}
+        <li><a href="#" aria-label="Next"><i class="fa-solid fa-chevron-right" aria-hidden></i></a></li>
+        {{/pagination.showNext}}
+    </ul>
+</div>
+{{/pagination.showPagination}}
\ No newline at end of file
diff --git a/stories/widgets/eclipsefdn-paginated-video-list.stories.ts b/stories/widgets/eclipsefdn-paginated-video-list.stories.ts
new file mode 100644
index 0000000000000000000000000000000000000000..18536e471263868f796b31c00a9bac98a086cc07
--- /dev/null
+++ b/stories/widgets/eclipsefdn-paginated-video-list.stories.ts
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2024 Eclipse Foundation, Inc.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+
+import '../../less/astro/main.less';
+
+import type { StoryObj } from '@storybook/html';
+import { container, afterStoryRender } from '../utils';
+import eclipsefdnPaginatedVideoList from '../../js/solstice/eclipsefdn.paginated-video-list';
+
+export default {
+  title: 'Widgets/Paginated Video List',
+  decorators: [container()],
+};
+
+type Story = StoryObj<any>;
+
+const commonOptions: Partial<Story> = {
+  argTypes: {
+    filterable: { control: 'boolean' },
+    count: { control: 'number' },
+  },
+  args: {
+    filterable: true,
+    count: 3,
+  },
+};
+
+export const PaginatedVideoList: Story = {
+  ...commonOptions,
+  render: ({ count, filterable }) => {
+    afterStoryRender(eclipsefdnPaginatedVideoList.render);
+
+    return `
+      <div class="eclipsefdn-paginated-video-list" data-count="${count}" data-filterable="${filterable}">
+        <div class="video-item" 
+            data-id="wrJUam_De6w"
+            data-title="Sven Erik Jeroschewski, Open Source Developer at Bosch.io, Project Lead Eclipse Kuksa"
+            data-date="November 30, 2022"
+            data-description="Sven Erik from Bosch.io explains how the Eclipse Kuksa project was combined with other Eclipse SDV projects for the first software-defined vehicle hackathon challenge that happened last month."
+            data-category="sdv-community-interviews-sep-2022">
+        </div>
+        <div class="video-item" 
+            data-id="s8GdAt40AJ0"
+            data-title="Interview with Fillipe Prezado and Audrey Colle during the SDV Hackathon at BCX"
+            data-date="November 30, 2022"
+            data-description="During the SDV Hackathon at BCX, Sara Gallian, our Software Defined Vehicle Working Group Program Manager caught up with Fillipe who is also the project lead of Eclipse Chariott."
+            data-category="sdv-community-interviews-sep-2022">
+        </div>
+        <div class="video-item" 
+            data-id="G6BhLZsPztk"
+            data-title="Industrial IoT Security: Best Practice for Authentication"
+            data-date="June 2, 2022"
+            data-description="Henrike Gerbothe and Jürgen Fitschen speak at IoT & Edge Days 2022"
+            data-category="virtual-iot-2022">
+        </div>
+        <div class="video-item" 
+            data-id="8a9xRfejmFI"
+            data-title="High Performance Network Programming in Rust"
+            data-date="June 2, 2022"
+            data-description="Angelo Corsaro speaks at IoT & Edge Days 2022. The Eclipse Zenoh team has been using Rust for quite a few years to build the entire Zenoh stack."
+            data-category="virtual-iot-2022">
+        </div>
+        <div class="video-item" 
+            data-id="mChxRJ23Rdw"
+            data-title="Eclipse IoT: The Next Ten Years"
+            data-date="June 2, 2022"
+            data-description="Frédéric Desbiens speaks at IoT & Edge Days 2022. Eclipse IoT celebrated its 10th anniversary in October 2021."
+            data-category="virtual-iot-2022">
+        </div>
+      </div>
+    `;
+  },
+};