(Squarespace) How to change Event Calendar to Carousel format on Mobile

#1. First, find Event Page URL

In my example, it is: /events-new

#2. Next, add a List People Carousel under Event Calendar

#3. Enable Title, Image Only

#4. Next, find ID of Event Calendar Section + Carousel Section Event Calendar

Carousel Section

#5. Use this code to Custom CSS

li.list-item .event-date-badge {
    position: absolute;
    top: 0px;
    left: 0px;
    background-color: #fff;
    color: #000;
    font-size: 18px;
    width: 60px;
    height: 60px;
}
li.list-item .date-badge-content {
    line-height: 20px;
    display: flex;
    align-items: center;
    flex-direction: column;
    justify-content: center;
    text-align: center;
    height: 100%;
}
body:not(.sqs-edit-mode-active) {
  /* hide carousel on desktop */
  @media screen and (min-width:768px) {
    section[data-section-id="68ba3fa1f98af504457516c3"] {
      display: none;
    }
  }
  /* hide Event Calendar on Mobile */
  @media screen and (max-width:767px) {
    section[data-section-id="68a58bbbdf53224db1b087ce"] {
      display: none;
    }
  }
}

Remember to update ID of both sections

#6. Use this code to Code Injection > Footer

<script>
class EventCarouselSync{constructor(options){this.eventEndpoint=options.eventUrl||"/events-new";this.config=options;this.carouselSection=this.config.target;this.carouselSection.dataset.eventSync="loading";this.eventData=[];this.carouselItems=this.carouselSection.querySelectorAll("li.user-items-list-carousel__slide");this.carouselContainer=this.carouselSection.querySelector(".user-items-list-carousel__slides");this.initialize()}
async initialize(){try{this.eventData=await this.fetchEventData();console.log("Fetched events:",this.eventData.length);console.log("Current carousel items:",this.carouselItems.length);while(this.carouselItems.length<this.eventData.length){console.log("Creating new slide...");const newSlide=this.createNewSlide();this.carouselContainer.appendChild(newSlide);this.carouselItems=this.carouselSection.querySelectorAll("li.user-items-list-carousel__slide");console.log("Total slides now:",this.carouselItems.length)}
if(this.carouselItems.length>this.eventData.length){console.warn("Too many carousel items, removing excess");while(this.carouselItems.length>this.eventData.length){this.carouselItems[this.carouselItems.length-1].remove();this.carouselItems=this.carouselSection.querySelectorAll("li.user-items-list-carousel__slide")}}
this.createItemTemplate();this.populateCarouselItems();this.carouselSection.dataset.eventSync="complete";console.log("Sync completed with",this.carouselItems.length,"items")}catch(error){console.error("Event Carousel Sync failed:",error);this.carouselSection.dataset.eventSync="error"}}
async fetchEventData(endpoint=this.eventEndpoint,collection=[]){try{const apiUrl=new URL(endpoint,window.location.origin);const params=new URLSearchParams(apiUrl.search);const timestamp=new Date().getTime();params.set("format","json");params.set("_t",timestamp);apiUrl.search=params.toString();const response=await fetch(apiUrl.toString());if(!response.ok){throw new Error(`API request failed: ${response.status}`)}
const data=await response.json();let events=data.upcoming||[];events.forEach(event=>collection.push(event));return collection}catch(error){console.error("Error loading event data:",error);throw error}}
createNewSlide(){const slideTemplate=`
      <li class="user-items-list-carousel__slide list-item" data-is-card-enabled="false">
        <div class="user-items-list-carousel__media-container" style="margin-bottom: 4%; width: 100%;">
          <div class="user-items-list-carousel__media-inner preFade fadeIn" data-media-aspect-ratio="4:3" data-animation-role="image">
            <img class="user-items-list-carousel__media" data-load="false" data-mode="cover" data-use-advanced-positioning="true" style="width: 100%; height: 100%; object-fit: cover;" data-parent-ratio="1.3" loading="lazy" decoding="async" data-loader="sqs">
          </div>
        </div>
        <div class="list-item-content">
          <div class="list-item-content__text-wrapper">
            <h2 class="list-item-content__title preFade" style="max-width: 100%;"></h2>
          </div>
        </div>
      </li>
    `;const tempDiv=document.createElement('div');tempDiv.innerHTML=slideTemplate;return tempDiv.firstElementChild}
createItemTemplate(){if(this.carouselItems.length>0){const templateHTML=this.carouselItems[0].innerHTML;this.carouselItems.forEach(item=>{item.innerHTML=templateHTML})}}
populateCarouselItems(){console.log("Populating",this.carouselItems.length,"items with",this.eventData.length,"events");for(let[index,carouselItem]of this.carouselItems.entries()){if(!this.eventData[index]){console.log("No event data for index",index);continue}
console.log("Processing event",index,":",this.eventData[index].title);const{title:eventTitle,assetUrl:eventImage,startDate:eventStart,fullUrl:eventLink}=this.eventData[index];let imageUrl=new URL(eventImage);let imageParams=new URLSearchParams(imageUrl.search);imageParams.set("syncedCarousel","true");imageUrl.search=imageParams.toString();let titleElement=carouselItem.querySelector(".list-item-content__title");let imageElement=carouselItem.querySelector("img");let mediaWrapper=carouselItem.querySelector(".user-items-list-carousel__media-container");if(titleElement){if(this.config.linkTitle){titleElement.innerHTML=`<a href="${eventLink}">${eventTitle}</a>`}else{titleElement.innerHTML=`<span>${eventTitle}</span>`}}
if(imageElement){let newImage=imageElement.cloneNode(!0);newImage.src=imageUrl;newImage.dataset.src=imageUrl;newImage.dataset.image=imageUrl;newImage.srcset="";newImage.alt=eventTitle;imageElement.parentElement.append(newImage);this.addEventDateOverlay(mediaWrapper,eventStart);imageElement.style.display="none"}}
window.dispatchEvent(new Event("resize"))}
addEventDateOverlay(container,startDate){if(!container||!startDate)return;let existingDateBadge=container.querySelector('.event-date-badge');if(existingDateBadge){existingDateBadge.remove()}
const dateOverlay=document.createElement("div");const eventDate=new Date(startDate);dateOverlay.classList.add("event-date-badge");dateOverlay.innerHTML=`<div class="date-badge-content">
      <div class="date-month">${eventDate.toLocaleDateString("en-US", {month: "short"})}</div>
      <div class="date-day">${eventDate.getDate()}</div>
    </div>`;container.style.position="relative";container.appendChild(dateOverlay)}
setupEventHandlers(){window.addEventListener("DOMContentLoaded",()=>{this.populateCarouselItems()});window.addEventListener("load",()=>{this.populateCarouselItems()})}
handleCarouselController(){const controllerElement=this.carouselSection.querySelector("[data-controller]");const observer=new MutationObserver((mutations)=>{mutations.forEach((mutation)=>{if(mutation.attributeName==="data-controllers-bound"&&controllerElement.dataset.controllersBound==="UserItemsListCarousel"){controllerElement.removeAttribute("data-controller");observer.disconnect()}})});if(controllerElement&&controllerElement.dataset.controllersBound==="UserItemsListCarousel"){controllerElement.removeAttribute("data-controller")}else if(controllerElement){observer.observe(controllerElement,{attributes:!0,attributeFilter:["data-controllers-bound"]})}}}(function(){const initEventCarouselSync=()=>{const carouselSections=document.querySelectorAll(".user-items-list-carousel");carouselSections.forEach(section=>{if(section.dataset.eventSync)return;const config={target:section.closest(".page-section"),linkTitle:!0,linkImage:!1};if(config.target){config.target.EventCarouselSync=new EventCarouselSync(config)}else{section.dataset.eventSync="no-target"}})};window.eventCarouselSync={init:initEventCarouselSync};initEventCarouselSync()})()
</script>

Remember to change Event Page URL

#7. To change Carousel to 2 items/row on Mobile, use this extra code under #5 code in Custom CSS box.

section:has(.event-date-badge) ul {
    grid-template-columns: repeat(2,1fr) !important;
}