Social Proof

Testimonial Slider

A testimonial slider with image, quote, author info, and logo.

View codeGitHub
Testimonial Slider preview 1

What you can change

  1. Split Image + Text Layout

    A two-column desktop layout with the image on the left and content on the right. The image column width is adjustable (30–60%). On mobile, the columns stack vertically.

  2. Arrow, Dot & Swipe Navigation

    Toggle arrow buttons and pagination dots independently. Arrow button size is adjustable via a range slider. Swipe left or right on touch devices to navigate between testimonials.

  3. Per-Slide Logo & Placeholder

    Each slide supports an optional logo image with alt text. When no logo is uploaded, a unique SVG placeholder keeps the layout polished.

  4. Customizability

    Full desktop/mobile padding controls, column gap slider, image aspect ratio and border radius, independent font size sliders for quote (desktop/mobile), author name, and position text, color pickers for background, text, and the divider line between author info and logo.

  5. Accessibility

    Semantic HTML with ARIA labels on navigation elements and proper image alt attributes.

props-testimonials-slider.liquid773 lines · Liquid
{%- comment -%}  Testimonial Slider | PROPS — https://props.tools/{%- endcomment -%} {% schema %}{  "name": "Testimonial Slider",  "tag": "section",  "class": "props-testimonials-slider",  "disabled_on": {    "groups": ["header", "custom.popups"]  },  "settings": [    {      "type": "header",      "content": "Layout"    },    {      "type": "range",      "id": "image_width_desktop",      "min": 30,      "max": 60,      "step": 1,      "unit": "%",      "label": "Image Width (Desktop)",      "default": 42    },    {      "type": "range",      "id": "column_gap",      "min": 0,      "max": 100,      "step": 4,      "unit": "px",      "label": "Column Gap (Desktop)",      "default": 60    },    {      "type": "header",      "content": "Typography"    },    {      "type": "range",      "id": "quote_size_desktop",      "min":12,      "max": 48,      "step": 1,      "unit": "px",      "label": "Quote Font Size",      "default": 16    },    {      "type": "range",      "id": "quote_size_mobile",      "min": 10,      "max": 32,      "step": 1,      "unit": "px",      "label": "Quote Font Size (Mobile)",      "default": 14    },    {      "type": "range",      "id": "author_name_size",      "min": 12,      "max": 24,      "step": 1,      "unit": "px",      "label": "Author Font Size",      "default": 15    },    {      "type": "range",      "id": "author_position_size",      "min": 10,      "max": 20,      "step": 1,      "unit": "px",      "label": "Company Font Size",      "default": 13    },    {      "type": "header",      "content": "Image Settings"    },    {      "type": "select",      "id": "image_aspect_ratio",      "label": "Image Aspect Ratio",      "options": [        { "value": "auto", "label": "Auto (Original)" },        { "value": "1/1", "label": "Square (1:1)" },        { "value": "3/4", "label": "Portrait (3:4)" },        { "value": "4/5", "label": "Tall Portrait (4:5)" },        { "value": "4/3", "label": "Landscape (4:3)" },        { "value": "16/9", "label": "Widescreen (16:9)" }      ],      "default": "auto"    },    {      "type": "range",      "id": "image_radius",      "min": 0,      "max": 24,      "step": 2,      "unit": "px",      "label": "Image Border Radius",      "default": 0    },    {      "type": "header",      "content": "Logo Settings"    },    {      "type": "range",      "id": "logo_height",      "min": 16,      "max": 80,      "step": 2,      "unit": "px",      "label": "Logo Height",      "default": 28    },    {      "type": "header",      "content": "Navigation"    },    {      "type": "checkbox",      "id": "show_dots",      "label": "Show Pagination Dots",      "default": true    },    {      "type": "checkbox",      "id": "show_arrows",      "label": "Show Navigation Arrows",      "default": true    },    {      "type": "range",      "id": "arrow_size",      "min": 32,      "max": 56,      "step": 2,      "unit": "px",      "label": "Arrow Button Size",      "default": 44    },    {      "type": "header",      "content": "Section Padding"    },    {      "type": "range",      "id": "padding_vertical_desktop",      "min": 0,      "max": 120,      "step": 4,      "unit": "px",      "label": "Vertical Padding",      "default": 80    },    {      "type": "range",      "id": "padding_horizontal_desktop",      "min": 0,      "max": 120,      "step": 4,      "unit": "px",      "label": "Horizontal Padding",      "default": 40    },    {      "type": "range",      "id": "padding_vertical_mobile",      "min": 0,      "max": 80,      "step": 4,      "unit": "px",      "label": "Vertical Padding (Mobile)",      "default": 40    },    {      "type": "range",      "id": "padding_horizontal_mobile",      "min": 0,      "max": 80,      "step": 4,      "unit": "px",      "label": "Horizontal Padding (Mobile)",      "default": 20    },    {      "type": "header",      "content": "Colors"    },    {      "type": "color",      "id": "bg_color",      "label": "Background Color",      "default": "transparent"    },    {      "type": "color",      "id": "text_color",      "label": "Text Color",      "default": "#121212"    },    {      "type": "color",      "id": "divider_color",      "label": "Divider Color",      "default": "#CCCCCC"    }  ],  "blocks": [    {      "type": "testimonial",      "name": "Testimonial",      "settings": [        {          "type": "image_picker",          "id": "image",          "label": "Image"        },        {          "type": "text",          "id": "alt_text",          "label": "Image Alt Text"        },        {          "type": "richtext",          "id": "quote",          "label": "Quote",          "default": "<p>\"PROPS has completely transformed our workflow. The sections are beautifully designed and incredibly easy to customize.\"</p>"        },        {          "type": "text",          "id": "author_name",          "label": "Author Name",          "default": "Alex Carter"        },        {          "type": "text",          "id": "author_position",          "label": "Position / Company",          "default": "Product Designer"        },        {          "type": "image_picker",          "id": "logo",          "label": "Logo / Image"        },        {          "type": "text",          "id": "logo_alt_text",          "label": "Logo Alt Text"        }      ]    }  ],  "presets": [    {      "name": "Testimonial Slider",      "blocks": [        {          "type": "testimonial",          "settings": {            "quote": "<p>\"PROPS has completely transformed our workflow. The sections are beautifully designed and incredibly easy to customize.\"</p>",            "author_name": "Alex Carter",            "author_position": "Product Designer"          }        },        {          "type": "testimonial",          "settings": {            "quote": "<p>\"We launched our store in half the time thanks to PROPS. Every section just works out of the box.\"</p>",            "author_name": "Samantha Lee",            "author_position": "Founder & CEO"          }        },        {          "type": "testimonial",          "settings": {            "quote": "<p>\"The attention to detail is unmatched. PROPS gave our site a premium feel without the development overhead.\"</p>",            "author_name": "Jordan Kim",            "author_position": "Frontend Engineer"          }        },        {          "type": "testimonial",          "settings": {            "quote": "<p>\"Hands down the best Shopify sections we've used. Clean code, beautiful defaults, and endlessly customizable.\"</p>",            "author_name": "Daniel White",            "author_position": "Head of Design"          }        },        {          "type": "testimonial",          "settings": {            "quote": "<p>\"PROPS made it possible for our small team to build a store that looks like it was done by an agency.\"</p>",            "author_name": "Maria Gonzalez",            "author_position": "Creative Director"          }        }      ]    }  ]}{% endschema %} {% style %}  .props-testimonials-slider-{{ section.id }} {    background-color: {{ section.settings.bg_color }};    color: {{ section.settings.text_color }};    padding-top: {{ section.settings.padding_vertical_mobile }}px;    padding-bottom: {{ section.settings.padding_vertical_mobile }}px;     --props-pd-h-m: {{ section.settings.padding_horizontal_mobile }}px;    --props-pd-h-d: {{ section.settings.padding_horizontal_desktop }}px;     --props-quote-size: {{ section.settings.quote_size_mobile }}px;    --props-author-name-size: {{ section.settings.author_name_size }}px;    --props-author-position-size: {{ section.settings.author_position_size }}px;    --props-logo-height: {{ section.settings.logo_height }}px;    --props-image-radius: {{ section.settings.image_radius }}px;    --props-column-gap: {{ section.settings.column_gap }}px;    --props-image-width: 100%;    --props-arrow-size: {{ section.settings.arrow_size }}px;    --props-divider-color: {{ section.settings.divider_color }};  }   @media screen and (min-width: 750px) {    .props-testimonials-slider-{{ section.id }} {      padding-top: {{ section.settings.padding_vertical_desktop }}px;      padding-bottom: {{ section.settings.padding_vertical_desktop }}px;       --props-quote-size: {{ section.settings.quote_size_desktop }}px;      --props-image-width: {{ section.settings.image_width_desktop }}%;    }  }   .props-testimonials-slider-container {    width: 100%;    max-width: var(--page-width, 1200px);    margin: 0 auto;    padding-left: var(--props-pd-h-m);    padding-right: var(--props-pd-h-m);    box-sizing: border-box;  }   @media screen and (min-width: 750px) {    .props-testimonials-slider-container {      padding-left: var(--props-pd-h-d);      padding-right: var(--props-pd-h-d);    }  }   .props-testimonials-slider-slides {    position: relative;  }   .props-testimonials-slider-slide {    position: absolute;    top: 0;    left: 0;    width: 100%;    opacity: 0;    pointer-events: none;    transition: opacity 0.4s ease;    z-index: 1;  }   .props-testimonials-slider-slide.active {    position: relative;    opacity: 1;    pointer-events: auto;    z-index: 2;  }   .props-testimonials-slider-layout {    display: flex;    flex-direction: column-reverse;    gap: 32px;  }   @media screen and (min-width: 750px) {    .props-testimonials-slider-layout {      flex-direction: row;      align-items: stretch;      gap: var(--props-column-gap);    }  }   .props-testimonials-slider-image-col {    width: 100%;    flex-shrink: 0;  }   @media screen and (min-width: 750px) {    .props-testimonials-slider-image-col {      width: var(--props-image-width);      flex: 0 0 var(--props-image-width);    }  }   .props-testimonials-slider-media {    width: 100%;    overflow: hidden;    border-radius: var(--props-image-radius);    {% unless section.settings.image_aspect_ratio == 'auto' %}      aspect-ratio: {{ section.settings.image_aspect_ratio }};    {% endunless %}    position: relative;    display: block;  }   .props-testimonials-slider-img {    width: 100%;    height: 100%;    display: block;    object-fit: cover;    {% unless section.settings.image_aspect_ratio == 'auto' %}      position: absolute;      top: 0;      left: 0;    {% endunless %}  }   .props-testimonials-slider-placeholder {    aspect-ratio: 1200 / 630;    height: auto;  }   .props-testimonials-slider-content-col {    flex: 1;    min-width: 0;    display: flex;    flex-direction: column;    justify-content: center;  }   .props-testimonials-slider-content-inner {    display: flex;    flex-direction: column;    gap: 28px;  }   .props-testimonials-slider-quote {    font-size: var(--props-quote-size);    line-height: 1.5;    font-weight: 500;    color: inherit;  }   .props-testimonials-slider-quote p {    margin: 0;  }  .props-testimonials-slider-quote a {    color: inherit;    text-decoration: underline;    text-underline-offset: 0.3em;  }   .props-testimonials-slider-attribution {    display: flex;    align-items: center;    gap: 20px;  }   .props-testimonials-slider-author-info {    display: flex;    flex-direction: column;    gap: 2px;  }   .props-testimonials-slider-author-name {    font-size: var(--props-author-name-size);    font-weight: 600;    line-height: 1.3;    color: inherit;  }   .props-testimonials-slider-author-position {    font-size: var(--props-author-position-size);    line-height: 1.3;    color: inherit;    opacity: 0.6;  }   .props-testimonials-slider-divider {    width: 1px;    align-self: stretch;    background-color: var(--props-divider-color);    flex-shrink: 0;  }   .props-testimonials-slider-logo {    display: block;    height: var(--props-logo-height);    width: auto;    object-fit: contain;  }   .props-testimonials-slider-placeholder-logo {    display: block;    height: var(--props-logo-height);    width: auto;  }   .props-testimonials-slider-controls {    display: flex;    align-items: center;    justify-content: space-between;    margin-top: 32px;  }   @media screen and (max-width: 749px) {    .props-testimonials-slider-controls {      margin-top: 24px;      margin-bottom: 0;    }     .props-testimonials-slider-controls-mobile-top {      order: -1;    }     .props-testimonials-slider-arrow {      width: calc(var(--props-arrow-size) * 0.6);      height: calc(var(--props-arrow-size) * 0.6);    }     .props-testimonials-slider-arrow svg {      width: 14px;      height: 14px;    }  }   .props-testimonials-slider-dots {    display: flex;    gap: 8px;    align-items: center;  }   .props-testimonials-slider-dot {    width: 8px;    height: 8px;    border-radius: 50%;    background: currentColor;    opacity: 0.2;    border: none;    padding: 0;    cursor: pointer;    transition: opacity 0.2s ease;  }   .props-testimonials-slider-dot.active {    opacity: 1;  }   .props-testimonials-slider-nav {    display: flex;    gap: 8px;  }   .props-testimonials-slider-arrow {    width: var(--props-arrow-size);    height: var(--props-arrow-size);    border-radius: 50%;    border: 1px solid currentColor;    background: transparent;    color: inherit;    display: flex;    align-items: center;    justify-content: center;    cursor: pointer;    padding: 0;    transition: opacity 0.2s ease;  }   @media (hover: hover) {    .props-testimonials-slider-arrow:hover {      opacity: 0.6;    }  }   .props-testimonials-slider-arrow svg {    width: 20px;    height: 20px;  }   @media screen and (max-width: 749px) {    .props-testimonials-slider-mobile-wrapper {      display: flex;      flex-direction: column;    }  }{% endstyle %} {%- liquid  assign block_count = section.blocks.size  assign has_blocks = false  if block_count > 0    assign has_blocks = true  endif-%} <div  class="props-testimonials-slider-{{ section.id }}"  data-section-type="props-testimonials-slider"  data-section-id="{{ section.id }}">  {% if has_blocks %}    <div class="props-testimonials-slider-container">      <div class="props-testimonials-slider-mobile-wrapper">        <div class="props-testimonials-slider-slides" id="Slides-{{ section.id }}">          {% for block in section.blocks %}            {%- assign placeholder_index = forloop.index | modulo: 6 -%}            <div class="props-testimonials-slider-slide {% if forloop.first %}active{% endif %}" data-index="{{ forloop.index0 }}" {{ block.shopify_attributes }}>              <div class="props-testimonials-slider-layout">                 <div class="props-testimonials-slider-image-col">                  <div class="props-testimonials-slider-media">                    {% if block.settings.image != blank %}                      {{ block.settings.image | image_url: width: 1200 | image_tag:                        loading: 'lazy',                        class: 'props-testimonials-slider-img',                        alt: block.settings.alt_text | default: block.settings.image.alt,                        widths: '400, 600, 800, 1000, 1200',                        sizes: '(min-width: 750px) 40vw, 100vw'                      }}                    {% else %}                      {{ 'image' | placeholder_svg_tag: 'props-testimonials-slider-img props-testimonials-slider-placeholder' | replace: '<svg', '<svg aria-hidden="true" focusable="false"' }}                    {% endif %}                  </div>                </div>                 <div class="props-testimonials-slider-content-col">                  <div class="props-testimonials-slider-content-inner">                    {% if block.settings.quote != blank %}                      <div class="props-testimonials-slider-quote">{{ block.settings.quote }}</div>                    {% endif %}                     <div class="props-testimonials-slider-attribution">                      {% if block.settings.author_name != blank or block.settings.author_position != blank %}                        <div class="props-testimonials-slider-author-info">                          {% if block.settings.author_name != blank %}                            <span class="props-testimonials-slider-author-name">{{ block.settings.author_name | escape }}</span>                          {% endif %}                          {% if block.settings.author_position != blank %}                            <span class="props-testimonials-slider-author-position">{{ block.settings.author_position | escape }}</span>                          {% endif %}                        </div>                      {% endif %}                       {% if block.settings.logo != blank %}                        <div class="props-testimonials-slider-divider"></div>                        <div class="props-testimonials-slider-logo-wrap">                          {{ block.settings.logo | image_url: height: 160 | image_tag:                            loading: 'lazy',                            class: 'props-testimonials-slider-logo',                            alt: block.settings.logo_alt_text | default: block.settings.logo.alt,                            widths: '80, 120, 160, 240',                            sizes: '120px'                          }}                        </div>                      {% endif %}                    </div>                  </div>                </div>               </div>            </div>          {% endfor %}        </div>         <div class="props-testimonials-slider-controls">          {% if section.settings.show_dots %}            <div class="props-testimonials-slider-dots" id="Dots-{{ section.id }}">              {% for block in section.blocks %}                <button class="props-testimonials-slider-dot {% if forloop.first %}active{% endif %}" data-index="{{ forloop.index0 }}" aria-label="Go to testimonial {{ forloop.index }}"></button>              {% endfor %}            </div>          {% else %}            <div></div>          {% endif %}           {% if section.settings.show_arrows %}            <div class="props-testimonials-slider-nav">              <button class="props-testimonials-slider-arrow" id="Prev-{{ section.id }}" aria-label="Previous testimonial">                <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M15 18l-6-6 6-6"/></svg>              </button>              <button class="props-testimonials-slider-arrow" id="Next-{{ section.id }}" aria-label="Next testimonial">                <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M9 18l6-6-6-6"/></svg>              </button>            </div>          {% endif %}        </div>      </div>    </div>  {% endif %}</div> {% javascript %}(function () {  const init = (container) => {    const id = container.getAttribute('data-section-id');    if (!id) return;     const slidesWrap = document.getElementById('Slides-' + id);    const prevBtn = document.getElementById('Prev-' + id);    const nextBtn = document.getElementById('Next-' + id);    const dotsWrap = document.getElementById('Dots-' + id);    if (!slidesWrap) return;     const slides = slidesWrap.querySelectorAll('.props-testimonials-slider-slide');    const dots = dotsWrap ? dotsWrap.querySelectorAll('.props-testimonials-slider-dot') : [];    let current = 0;     const goTo = (index) => {      if (index < 0) index = slides.length - 1;      if (index >= slides.length) index = 0;      if (index === current) return;      slides.forEach((s, i) => s.classList.toggle('active', i === index));      dots.forEach((d, i) => d.classList.toggle('active', i === index));      current = index;    };     if (nextBtn) {      nextBtn.addEventListener('click', () => goTo(current + 1));    }     if (prevBtn) {      prevBtn.addEventListener('click', () => goTo(current - 1));    }     dots.forEach((dot) => {      dot.addEventListener('click', () => {        const idx = parseInt(dot.getAttribute('data-index'), 10);        goTo(idx);      });    });     let touchStartX = 0;    let touchEndX = 0;     slidesWrap.addEventListener('touchstart', (e) => {      touchStartX = e.changedTouches[0].screenX;    }, { passive: true });     slidesWrap.addEventListener('touchend', (e) => {      touchEndX = e.changedTouches[0].screenX;      const diff = touchStartX - touchEndX;      if (Math.abs(diff) > 50) {        if (diff > 0) {          goTo(current + 1);        } else {          goTo(current - 1);        }      }    }, { passive: true });  };   document.querySelectorAll('[data-section-type="props-testimonials-slider"]').forEach(init);   document.addEventListener('shopify:section:load', (e) => {    const c = e.target.querySelector('[data-section-type="props-testimonials-slider"]');    if (c) init(c);  });})();{% endjavascript %} 

Clashing with your theme?

Tell us which theme and what looks off. Every report becomes a public issue you can follow.

More like this

All sections