Image CarouselImage Carousel
GalleryText and ImageVideo Capable
← Back to Sections

Image Carousel

<div class="section-{{ section.id }}{% unless section.settings.use_custom_colors %} color-{{ section.settings.color_scheme }}{% endunless %}">
  {% if section.settings.heading_text != blank %}
    <div class="bc-carousel-heading">
      <div class="bc-heading">{{ section.settings.heading_text }}</div>
      {% if section.settings.subheading_text != blank %}
        <div class="bc-subheading">{{ section.settings.subheading_text }}</div>
      {% endif %}
    </div>
  {% endif %}

  <div class="bc-carousel-container">
    <div class="bc-carousel-track-container">
      <div class="bc-carousel-track" data-carousel-track>
        {% for block in section.blocks %}
          <div class="bc-carousel-slide" data-carousel-slide>
            {% if block.settings.video != blank %}
              {{
                block.settings.video
                | video_tag:
                  controls: false,
                  autoplay: true,
                  loop: true,
                  muted: true,
                  preload: 'auto',
                  loading: block.settings.video_loading,
                  class: 'bc-carousel-video'
              }}
            {% elsif block.settings.image %}
              <img
                src="{{ block.settings.image | img_url: '2048x' }}"
                alt="{{ block.settings.image_alt | default: block.settings.image.alt | default: 'Carousel image' }}"
                loading="{{ block.settings.image_loading }}"
                class="bc-carousel-image"
                style="opacity: {{ block.settings.image_opacity }}%;"
              >
            {% else %}
              <div class="bc-carousel-placeholder">
                <p>Add an image or video</p>
              </div>
            {% endif %}
          </div>
        {% endfor %}
      </div>

      <button class="bc-carousel-arrow bc-carousel-arrow--prev" data-carousel-prev>
        <div class="bc-icon" style="color: {{ section.settings.arrow_color }};">
          {% if section.settings.prev_arrow_icon_image != blank %}
            <img
              src="{{ section.settings.prev_arrow_icon_image | img_url: 'original' }}"
              alt="{{ section.settings.prev_arrow_icon_image_alt | default: 'Previous' }}"
              loading="lazy"
            >
          {% else %}
            {{
              section.settings.prev_arrow_icon_svg
              | default: '<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M15 18L9 12L15 6" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>'
            }}
          {% endif %}
        </div>
      </button>

      <button class="bc-carousel-arrow bc-carousel-arrow--next" data-carousel-next>
        <div class="bc-icon" style="color: {{ section.settings.arrow_color }};">
          {% if section.settings.next_arrow_icon_image != blank %}
            <img
              src="{{ section.settings.next_arrow_icon_image | img_url: 'original' }}"
              alt="{{ section.settings.next_arrow_icon_image_alt | default: 'Next' }}"
              loading="lazy"
            >
          {% else %}
            {{
              section.settings.next_arrow_icon_svg
              | default: '<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M9 18L15 12L9 6" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>'
            }}
          {% endif %}
        </div>
      </button>
    </div>
  </div>
</div>

{% comment %}  Designed and Developed by Bungalow Creative. Get sections like these at The Section Studio https://bungalowcreative.co/pages/the-section-studio {% endcomment %}

<style>
  .section-{{ section.id }} {
    width: 100%;
    position: relative;
    padding-top: {{ section.settings.padding_top }}px;
    padding-bottom: {{ section.settings.padding_bottom }}px;
    padding-left: {{ section.settings.padding_left_desktop }}px;
    padding-right: {{ section.settings.padding_right_desktop }}px;
    border-top: {{ section.settings.border_top_thickness }}px solid {{ section.settings.border_color }};
    border-bottom: {{ section.settings.border_bottom_thickness }}px solid {{ section.settings.border_color }};
    {% if section.settings.use_custom_colors %}
      background-color: {{ section.settings.background_color }};
      color: {{ section.settings.text_color }};
    {% else %}
      color: rgb(var(--color-foreground));
    {% endif %}
  }

  .section-{{ section.id }} .bc-carousel-heading {
    text-align: center;
    margin-bottom: 24px;
  }

  .section-{{ section.id }} .bc-heading * {
    font-size: clamp({{ section.settings.heading_size | times: section.settings.heading_mobile_scale_ratio }}rem, 4vw, {{ section.settings.heading_size }}rem) !important;
    line-height: {{ section.settings.heading_line_height }};
    max-width: {{ section.settings.heading_max_width }}ch;
    margin: 0 auto;
  }

  .section-{{ section.id }} .bc-subheading * {
    font-size: clamp({{ section.settings.subheading_size | times: section.settings.subheading_mobile_scale_ratio }}rem, 4vw, {{ section.settings.subheading_size }}rem) !important;
    line-height: {{ section.settings.subheading_line_height }};
    max-width: {{ section.settings.subheading_max_width }}ch;
    margin: 8px auto 0;
  }

  .section-{{ section.id }} .bc-carousel-container {
    width: 100%;
    position: relative;
  }

  .section-{{ section.id }} .bc-carousel-track-container {
    width: 100%;
    overflow: hidden;
    position: relative;
  }

  .section-{{ section.id }} .bc-carousel-track {
    display: flex;
    transition: transform 0.3s ease;
    width: 100%;
  }

  .section-{{ section.id }} .bc-carousel-slide {
    min-width: 100%;
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
  }

  .section-{{ section.id }} .bc-carousel-image {
    width: 100%;
    height: {{ section.settings.carousel_height }}px;
    object-fit: cover;
    object-position: center;
    display: block;
  }

  .section-{{ section.id }} .bc-carousel-video {
    width: 100%;
    height: {{ section.settings.carousel_height }}px;
    object-fit: cover;
    display: block;
    opacity: {{ section.settings.video_opacity }}%;
  }

  .section-{{ section.id }} .bc-carousel-placeholder {
    width: 100%;
    height: {{ section.settings.carousel_height }}px;
    background-color: #f5f5f5;
    display: flex;
    align-items: center;
    justify-content: center;
    color: #666;
  }

  .section-{{ section.id }} .bc-carousel-arrow {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    background: {{ section.settings.arrow_background_color }};
    border: 1px solid rgba(255, 255, 255, 0.3);
    border-radius: 50%;
    width: 48px;
    height: 48px;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    transition: all 0.2s ease;
    z-index: 10;
    backdrop-filter: blur(4px);
  }

  .section-{{ section.id }} .bc-carousel-arrow:hover {
    background: rgba(255, 255, 255, 1);
    border-color: rgba(255, 255, 255, 0.8);
    transform: translateY(-50%) scale(1.05);
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
  }

  .section-{{ section.id }} .bc-carousel-arrow:disabled {
    opacity: 0.4;
    cursor: not-allowed;
    transform: translateY(-50%);
  }

  .section-{{ section.id }} .bc-carousel-arrow--prev {
    left: 20px;
  }

  .section-{{ section.id }} .bc-carousel-arrow--next {
    right: 20px;
  }

  .section-{{ section.id }} .bc-icon svg {
    width: 100%;
    height: 100%;
    display: block;
  }

  .section-{{ section.id }} .bc-icon img {
    width: 100%;
    height: 100%;
    object-fit: contain;
    display: block;
  }

  @media (max-width: 991px) {
    .section-{{ section.id }} {
      padding-left: {{ section.settings.padding_left_tablet }}px;
      padding-right: {{ section.settings.padding_right_tablet }}px;
    }

    .section-{{ section.id }} .bc-carousel-image {
      height: calc({{ section.settings.carousel_height }}px * 0.8);
    }
    .section-{{ section.id }} .bc-carousel-video {
      height: calc({{ section.settings.carousel_height }}px * 0.8);
    }
    .section-{{ section.id }} .bc-carousel-placeholder {
      height: calc({{ section.settings.carousel_height }}px * 0.8);
    }
  }

  @media (max-width: 767px) {
    .section-{{ section.id }} {
      padding-left: {{ section.settings.padding_left_mobile }}px;
      padding-right: {{ section.settings.padding_right_mobile }}px;
    }

    .section-{{ section.id }} .bc-carousel-image {
      height: calc({{ section.settings.carousel_height }}px * 0.6);
    }
    .section-{{ section.id }} .bc-carousel-video {
      height: calc({{ section.settings.carousel_height }}px * 0.6);
    }
    .section-{{ section.id }} .bc-carousel-placeholder {
      height: calc({{ section.settings.carousel_height }}px * 0.6);
    }

    .section-{{ section.id }} .bc-carousel-arrow {
      width: 40px;
      height: 40px;
    }

    .section-{{ section.id }} .bc-carousel-arrow--prev {
      left: 12px;
    }

    .section-{{ section.id }} .bc-carousel-arrow--next {
      right: 12px;
    }
  }
</style>

<script>
  document.addEventListener('DOMContentLoaded', function() {
    const bcCarousel_{{ section.id }} = document.querySelector('.section-{{ section.id }} [data-carousel-track]')?.closest('.section-{{ section.id }}');
    
    if (bcCarousel_{{ section.id }}) {
      const track = bcCarousel_{{ section.id }}.querySelector('[data-carousel-track]');
      const slides = bcCarousel_{{ section.id }}.querySelectorAll('[data-carousel-slide]');
      const prevButton = bcCarousel_{{ section.id }}.querySelector('[data-carousel-prev]');
      const nextButton = bcCarousel_{{ section.id }}.querySelector('[data-carousel-next]');
      
      let currentSlide = 0;
      const totalSlides = slides.length;
      
      function updateCarousel() {
        const translateX = -currentSlide * 100;
        track.style.transform = `translateX(${translateX}%)`;
        
        prevButton.disabled = currentSlide === 0;
        nextButton.disabled = currentSlide === totalSlides - 1;
      }
      
      function goToNextSlide() {
        if (currentSlide < totalSlides - 1) {
          currentSlide++;
          updateCarousel();
        }
      }
      
      function goToPrevSlide() {
        if (currentSlide > 0) {
          currentSlide--;
          updateCarousel();
        }
      }
      
      nextButton.addEventListener('click', goToNextSlide);
      prevButton.addEventListener('click', goToPrevSlide);
      
      updateCarousel();
    }
  });
</script>

{% schema %}
{
  "name": "BC Image Carousel",
  "tag": "section",
  "class": "section",
  "settings": [
    {
      "type": "header",
      "content": "Colors"
    },
    {
      "type": "color_scheme",
      "id": "color_scheme",
      "label": "Color Scheme",
      "default": "scheme-1"
    },
    {
      "type": "checkbox",
      "id": "use_custom_colors",
      "label": "Use custom colors instead of a Dawn color scheme",
      "default": false
    },
    {
      "type": "color",
      "id": "background_color",
      "label": "Background Color",
      "default": "#ffffff"
    },
    {
      "type": "color",
      "id": "text_color",
      "label": "Text Color",
      "default": "#000000"
    },
    {
      "type": "color",
      "id": "border_color",
      "label": "Border Color",
      "default": "#000000"
    },
    {
      "type": "color",
      "id": "arrow_color",
      "label": "Arrow color",
      "default": "#333333"
    },
    {
      "type": "color",
      "id": "arrow_background_color",
      "label": "Arrow background color",
      "default": "rgba(255, 255, 255, 0.9)"
    },
    {
      "type": "header",
      "content": "Section Settings"
    },
    {
      "type": "range",
      "id": "padding_top",
      "min": 0,
      "max": 150,
      "step": 5,
      "unit": "px",
      "label": "Top padding",
      "default": 40
    },
    {
      "type": "range",
      "id": "padding_bottom",
      "min": 0,
      "max": 150,
      "step": 5,
      "unit": "px",
      "label": "Bottom padding",
      "default": 40
    },
    {
      "type": "range",
      "id": "padding_left_desktop",
      "min": 0,
      "max": 150,
      "step": 5,
      "unit": "px",
      "label": "Left padding (Desktop)",
      "default": 50
    },
    {
      "type": "range",
      "id": "padding_right_desktop",
      "min": 0,
      "max": 150,
      "step": 5,
      "unit": "px",
      "label": "Right padding (Desktop)",
      "default": 50
    },
    {
      "type": "range",
      "id": "padding_left_tablet",
      "min": 0,
      "max": 150,
      "step": 5,
      "unit": "px",
      "label": "Left padding (Tablet)",
      "default": 40
    },
    {
      "type": "range",
      "id": "padding_right_tablet",
      "min": 0,
      "max": 150,
      "step": 5,
      "unit": "px",
      "label": "Right padding (Tablet)",
      "default": 40
    },
    {
      "type": "range",
      "id": "padding_left_mobile",
      "min": 0,
      "max": 150,
      "step": 5,
      "unit": "px",
      "label": "Left padding (Mobile)",
      "default": 10
    },
    {
      "type": "range",
      "id": "padding_right_mobile",
      "min": 0,
      "max": 150,
      "step": 5,
      "unit": "px",
      "label": "Right padding (Mobile)",
      "default": 10
    },
    {
      "type": "range",
      "id": "border_top_thickness",
      "min": 0,
      "max": 10,
      "step": 1,
      "unit": "px",
      "label": "Top border thickness",
      "default": 0
    },
    {
      "type": "range",
      "id": "border_bottom_thickness",
      "min": 0,
      "max": 10,
      "step": 1,
      "unit": "px",
      "label": "Bottom border thickness",
      "default": 0
    },
    {
      "type": "range",
      "id": "carousel_height",
      "min": 200,
      "max": 800,
      "step": 50,
      "unit": "px",
      "label": "Carousel height (desktop)",
      "default": 400,
      "info": "Height automatically scales down on smaller screens to prevent cropping"
    },
    {
      "type": "header",
      "content": "Text Section"
    },
    {
      "type": "richtext",
      "id": "heading_text",
      "label": "Heading",
      "default": "<h2>Your Heading Goes Here</h2>"
    },
    {
      "type": "richtext",
      "id": "subheading_text",
      "label": "Subheading",
      "default": "<p>Your subheading text goes here</p>"
    },
    {
      "type": "range",
      "id": "heading_size",
      "label": "Heading Font Size",
      "min": 0.5,
      "max": 8,
      "step": 0.1,
      "default": 2.0,
      "unit": "rem",
      "info": "Font size in rem units (good for accessibility)"
    },
    {
      "type": "range",
      "id": "subheading_size",
      "label": "Subheading Font Size",
      "min": 0.5,
      "max": 8,
      "step": 0.1,
      "default": 1.4,
      "unit": "rem",
      "info": "Font size in rem units (good for accessibility)"
    },
    {
      "type": "range",
      "id": "heading_line_height",
      "label": "Heading Line Height",
      "min": 1,
      "max": 2,
      "step": 0.1,
      "default": 1.2
    },
    {
      "type": "range",
      "id": "subheading_line_height",
      "label": "Subheading Line Height",
      "min": 1,
      "max": 2,
      "step": 0.1,
      "default": 1.4
    },
    {
      "type": "range",
      "id": "heading_max_width",
      "label": "Heading Max Width",
      "min": 10,
      "max": 100,
      "step": 1,
      "default": 50,
      "unit": "ch"
    },
    {
      "type": "range",
      "id": "subheading_max_width",
      "label": "Subheading Max Width",
      "min": 10,
      "max": 100,
      "step": 1,
      "default": 60,
      "unit": "ch"
    },
    {
      "type": "range",
      "id": "heading_mobile_scale_ratio",
      "label": "Heading Mobile Scale Ratio",
      "min": 0.5,
      "max": 1,
      "step": 0.1,
      "default": 0.8,
      "unit": "Γ—",
      "info": "Controls how much heading text shrinks on smaller screens"
    },
    {
      "type": "range",
      "id": "subheading_mobile_scale_ratio",
      "label": "Subheading Mobile Scale Ratio",
      "min": 0.5,
      "max": 1,
      "step": 0.1,
      "default": 0.8,
      "unit": "Γ—",
      "info": "Controls how much subheading text shrinks on smaller screens"
    },
    {
      "type": "header",
      "content": "Media Section"
    },
    {
      "type": "range",
      "id": "video_opacity",
      "label": "Video Opacity",
      "min": 10,
      "max": 100,
      "step": 5,
      "unit": "%",
      "default": 100
    },
    {
      "type": "header",
      "content": "Arrow Icons"
    },
    {
      "type": "image_picker",
      "id": "prev_arrow_icon_image",
      "label": "Previous Arrow Icon Image (Optional)",
      "info": "Upload an image to use as the previous arrow icon. This takes precedence over SVG code if both are provided."
    },
    {
      "type": "text",
      "id": "prev_arrow_icon_image_alt",
      "label": "Previous Arrow Icon Image Alt Text",
      "placeholder": "e.g. Previous"
    },
    {
      "type": "textarea",
      "id": "prev_arrow_icon_svg",
      "label": "Previous Arrow SVG Icon Code",
      "info": "Paste the inline SVG code here. You can copy icons directly from https://lucide.dev/icons using the 'Copy SVG' button. Make sure the SVG uses 'stroke=\"currentColor\"' or 'fill=\"currentColor\"' so the color setting works."
    },
    {
      "type": "image_picker",
      "id": "next_arrow_icon_image",
      "label": "Next Arrow Icon Image (Optional)",
      "info": "Upload an image to use as the next arrow icon. This takes precedence over SVG code if both are provided."
    },
    {
      "type": "text",
      "id": "next_arrow_icon_image_alt",
      "label": "Next Arrow Icon Image Alt Text",
      "placeholder": "e.g. Next"
    },
    {
      "type": "textarea",
      "id": "next_arrow_icon_svg",
      "label": "Next Arrow SVG Icon Code",
      "info": "Paste the inline SVG code here. You can copy icons directly from https://lucide.dev/icons using the 'Copy SVG' button. Make sure the SVG uses 'stroke=\"currentColor\"' or 'fill=\"currentColor\"' so the color setting works."
    }
  ],
  "blocks": [
    {
      "type": "image",
      "name": "Media",
      "settings": [
        {
          "type": "image_picker",
          "id": "image",
          "label": "Image"
        },
        {
          "type": "video",
          "id": "video",
          "label": "Video",
          "info": "Video will take precedence over image if both are uploaded"
        },
        {
          "type": "text",
          "id": "image_alt",
          "label": "Image Alt Text",
          "placeholder": "e.g. Product showcase image"
        },
        {
          "type": "range",
          "id": "image_opacity",
          "label": "Image Opacity",
          "min": 10,
          "max": 100,
          "step": 5,
          "unit": "%",
          "default": 100
        },
        {
          "type": "select",
          "id": "image_loading",
          "label": "Image Loading",
          "options": [
            {
              "value": "lazy",
              "label": "Lazy"
            },
            {
              "value": "eager",
              "label": "Eager"
            }
          ],
          "default": "lazy"
        },
        {
          "type": "select",
          "id": "video_loading",
          "label": "Video Loading",
          "options": [
            {
              "value": "lazy",
              "label": "Lazy"
            },
            {
              "value": "eager",
              "label": "Eager"
            }
          ],
          "default": "lazy"
        }
      ]
    }
  ],
  "presets": [
    {
      "name": "BC Image Carousel",
      "blocks": [
        {
          "type": "image"
        },
        {
          "type": "image"
        },
        {
          "type": "image"
        }
      ]
    }
  ]
}
{% endschema %}