Buy me a coffee

Auto-advancing slider with a circular progress indicator

Description

12.25l22

#1. Install Code

First, you need to add a Team Section

12.25l22

Make sure enable these options.

12.25l22

and add your desired text/image/button

12.25l22

12.25l22

Hover on top right of section > Click Edit Section > At Anchor Link, enter word: mobile-slider

mobile-slider

12.25l22

Next, hover on page where you use Team Section > Click Gear icon

12.25l22

Click Advanced > Paste these code

<!-- Auto-advancing slider with a circular progress indicator - support [email protected] -->
<style>
section[id*="mobile-slider"]{
  /* CONTAINER & TYPO */
  --tp-slider-max-width: 420px;
  --tp-slider-bg-color: #ffffff;
  --tp-slider-text-color: #111;
  --tp-slider-font-family: system-ui,-apple-system,Segoe UI,Roboto,Arial,sans-serif;
  /* IMAGE STAGE */
  --tp-image-stage-bg: #f2f2f2;
  --tp-image-aspect-ratio-padding: 100%; /* 1:1 = 100%, 4:5 = 125%, 16:9 = 56.25% */
  /* SPACING */
  --tp-content-horizontal-padding: 18px;
  --tp-text-padding-top: 4px;
  --tp-text-padding-bottom: 18px;
  --tp-description-margin-top: 1%;
  --tp-button-margin-top: 2%;
  /* MOTION & TIMING */
  --tp-image-slide-duration: 900ms;
  --tp-text-slide-duration: 1350ms;
  --tp-autoplay-duration: 3600ms;
  --tp-slider-easing: cubic-bezier(.22,1,.36,1);
  /* DOT NAVIGATION */
  --tp-dots-gap: 12px;
  --tp-dots-padding-top: 14px;
  --tp-dots-padding-bottom: 8px;
  --tp-dot-button-size: 22px;
  --tp-dot-button-padding: 6px;
  --tp-dot-size: 6px;
  --tp-dot-color-inactive: rgba(17,17,17,.18);
  --tp-dot-color-active: rgba(17,17,17,.9);
  /* DOT PROGRESS RING */
  --tp-progress-ring-color: rgba(17,17,17,.9);
  --tp-progress-ring-stroke-width: 2.5;
  /* TEXT STYLES */
  --tp-title-font-size: 1.2rem;
  --tp-description-font-size: .9rem;
  --tp-button-font-size: .8rem;
}

section[id*="mobile-slider"] .tp-mob-slider{
  width:100%;
  max-width:var(--tp-slider-max-width);
  margin:0 auto;
  background:var(--tp-slider-bg-color);
  color:var(--tp-slider-text-color);
  font-family:var(--tp-slider-font-family);
  box-sizing:border-box;
}

section[id*="mobile-slider"] .tp-mob-stage{
  overflow:hidden;
  background:var(--tp-image-stage-bg);
}
section[id*="mobile-slider"] .tp-mob-viewport{ position:relative; width:100%; }
section[id*="mobile-slider"] .tp-mob-viewport::before{
  content:"";
  display:block;
  padding-top:var(--tp-image-aspect-ratio-padding);
}

section[id*="mobile-slider"] .tp-mob-track{
  position:absolute; inset:0;
  display:flex; width:100%; height:100%;
  transform:translate3d(0,0,0);
  transition:transform var(--tp-image-slide-duration) var(--tp-slider-easing);
  will-change:transform;
}
section[id*="mobile-slider"] .tp-mob-slide{
  flex:0 0 100%;
  width:100%; height:100%;
  position:relative;
}
section[id*="mobile-slider"] .tp-mob-slide img{
  position:absolute; inset:0;
  width:100%; height:100%;
  object-fit:cover;
  transform:translateZ(0);
}

section[id*="mobile-slider"] .tp-mob-dots{
  display:flex;
  justify-content:center;
  gap:var(--tp-dots-gap);
  padding:var(--tp-dots-padding-top) 0 var(--tp-dots-padding-bottom);
  user-select:none;
  -webkit-tap-highlight-color:transparent;
}
section[id*="mobile-slider"] .tp-dotbtn{
  appearance:none;
  border:0;
  background:transparent;
  cursor:pointer;
  position:relative;
  width:var(--tp-dot-button-size);
  height:var(--tp-dot-button-size);
  padding:var(--tp-dot-button-padding);
}
section[id*="mobile-slider"] .tp-dotcore{
  position:absolute;
  left:50%; top:50%;
  width:var(--tp-dot-size);
  height:var(--tp-dot-size);
  border-radius:999px;
  transform:translate(-50%,-50%);
  background:var(--tp-dot-color-inactive);
}
section[id*="mobile-slider"] .tp-dotbtn.is-active .tp-dotcore{
  background:var(--tp-dot-color-active);
}

section[id*="mobile-slider"] .tp-ring{
  position:absolute;
  inset:0;
  transform:rotate(-90deg);
}
section[id*="mobile-slider"] .tp-ring circle{
  fill:none;
  stroke:var(--tp-progress-ring-color);
  stroke-width:var(--tp-progress-ring-stroke-width);
  stroke-linecap:round;
  stroke-dasharray:100;
  stroke-dashoffset:100;
  opacity:0;
}
section[id*="mobile-slider"] .tp-dotbtn.is-active .tp-ring circle{
  opacity:1;
  animation:tpRing var(--tp-autoplay-duration) linear forwards;
}
@keyframes tpRing{
  from{ stroke-dashoffset:100; }
  to{ stroke-dashoffset:0; }
}

section[id*="mobile-slider"] .tp-mob-text{
  padding:
    var(--tp-text-padding-top)
    var(--tp-content-horizontal-padding)
    var(--tp-text-padding-bottom);
}
section[id*="mobile-slider"] .tp-text-viewport{ overflow:hidden; }
section[id*="mobile-slider"] .tp-text-track{
  display:flex;
  transform:translate3d(0,0,0);
  transition:
    transform var(--tp-text-slide-duration) var(--tp-slider-easing),
    opacity 380ms ease;
  will-change:transform, opacity;
  opacity:1;
}
section[id*="mobile-slider"] .tp-mob-slider.is-leaving .tp-text-track{
  opacity:0;
}
section[id*="mobile-slider"] .tp-text-slide{
  flex:0 0 100%;
  width:100%;
}

section[id*="mobile-slider"] .tp-text-slide .list-item-content__title{
  margin:inherit;
  font-size:var(--tp-title-font-size) !important;
}
section[id*="mobile-slider"] .tp-text-slide .list-item-content__description{
  font-size:var(--tp-description-font-size) !important;
  margin-top:var(--tp-description-margin-top);
}
section[id*="mobile-slider"] .tp-text-slide .list-item-content__button-container{
  margin-top:var(--tp-button-margin-top);
  max-width:100%;
}
section[id*="mobile-slider"] .tp-text-slide .list-item-content__button{
  font-size:var(--tp-button-font-size) !important;
}

section[id*="mobile-slider"].tp-ms-ready .user-items-list{
  display:none !important;
}
</style>

<script>
(function(){
  const $$=(s,r)=>Array.prototype.slice.call((r||document).querySelectorAll(s));
  const strip=(html)=>{const d=document.createElement("div");d.innerHTML=String(html||"");return (d.textContent||"").replace(/\s+/g," ").trim();};
  const imgFrom=(li)=>{const im=li.querySelector("img");return im?(im.getAttribute("data-src")||im.getAttribute("data-image")||im.currentSrc||im.src||""):"";};
  const firstNonEmpty=(...v)=>v.find(x=>String(x||"").trim())||"#";

  function readSlides(section){
    const ul=section.querySelector(".user-items-list-item-container");
    if(!ul) return [];
    const items=$$("li.list-item", ul);

    return items.map((li,i)=>{
      const titleHTML=li.querySelector(".list-item-content__title")?.innerHTML||"";
      const descNode=li.querySelector(".list-item-content__description");
      const descHTML=descNode ? descNode.innerHTML : "";
      const a=li.querySelector(".list-item-content__button");
      const btnText=strip(a?.innerHTML||a?.textContent||"");
      const btnHref=firstNonEmpty(a?.getAttribute("href"), "#");
      const btnClass=(a && a.getAttribute("class")) ? a.getAttribute("class") : "list-item-content__button sqs-block-button-element sqs-block-button-element--medium sqs-button-element--primary";
      const img=imgFrom(li);
      return {img,titleHTML,descHTML,btnText,btnHref,btnClass,i};
    }).filter(s=>s.img || strip(s.titleHTML) || strip(s.descHTML));
  }

  function build(section, slides){
    let root=section.querySelector(".tp-mob-slider");
    if(!root){ root=document.createElement("div"); root.className="tp-mob-slider"; }

    const cs=getComputedStyle(section);
    const dur=Math.max(1200, parseFloat(cs.getPropertyValue("--tp-dur"))||3600);
    const imgAnim=Math.max(250, parseFloat(cs.getPropertyValue("--tp-img-dur"))||900);
    const textAnim=Math.max(imgAnim, parseFloat(cs.getPropertyValue("--tp-text-dur"))||1350);
    root.style.setProperty("--tp-dur", dur+"ms");
    root.style.setProperty("--tp-img-dur", imgAnim+"ms");
    root.style.setProperty("--tp-text-dur", textAnim+"ms");

    const stage=document.createElement("div"); stage.className="tp-mob-stage";
    const viewport=document.createElement("div"); viewport.className="tp-mob-viewport";
    const track=document.createElement("div"); track.className="tp-mob-track";

    slides.forEach((s,i)=>{
      const sl=document.createElement("div"); sl.className="tp-mob-slide";
      const im=document.createElement("img");
      im.loading="lazy"; im.alt=strip(s.titleHTML)||("Slide "+(i+1)); im.src=s.img||"";
      sl.appendChild(im); track.appendChild(sl);
    });

    viewport.appendChild(track); stage.appendChild(viewport);

    const dots=document.createElement("div"); dots.className="tp-mob-dots";
    const dotBtns=slides.map((s,i)=>{
      const b=document.createElement("button");
      b.type="button";
      b.className="tp-dotbtn"+(i===0?" is-active":"");
      b.setAttribute("aria-label","Go to slide "+(i+1));
      const core=document.createElement("span"); core.className="tp-dotcore";
      const svg=document.createElementNS("http://www.w3.org/2000/svg","svg");
      svg.setAttribute("class","tp-ring"); svg.setAttribute("viewBox","0 0 36 36");
      const c=document.createElementNS("http://www.w3.org/2000/svg","circle");
      c.setAttribute("cx","18"); c.setAttribute("cy","18"); c.setAttribute("r","15.9155");
      svg.appendChild(c);
      b.appendChild(core); b.appendChild(svg);
      dots.appendChild(b);
      return b;
    });

    const textWrap=document.createElement("div"); textWrap.className="tp-mob-text";
    const textViewport=document.createElement("div"); textViewport.className="tp-text-viewport";
    const textTrack=document.createElement("div"); textTrack.className="tp-text-track";

    slides.forEach((s)=>{
      const ts=document.createElement("div"); ts.className="tp-text-slide";

      const title=document.createElement("h2");
      title.className="list-item-content__title";
      title.style.maxWidth="100%";
      title.innerHTML=s.titleHTML||"";

      const desc=document.createElement("div");
      desc.className="list-item-content__description";
      desc.style.marginTop="1%";
      desc.style.maxWidth="100%";
      if(s.descHTML){
        desc.innerHTML=s.descHTML;
      }else{
        const p=document.createElement("p");
        p.setAttribute("data-rte-preserve-empty","true");
        p.style.whiteSpace="pre-wrap";
        p.textContent="";
        desc.appendChild(p);
      }

      const btnWrap=document.createElement("div");
      btnWrap.className="list-item-content__button-wrapper";

      const btnContainer=document.createElement("div");
      btnContainer.className="list-item-content__button-container";
      btnContainer.style.marginTop="2%";
      btnContainer.style.maxWidth="100%";
      btnContainer.setAttribute("data-animation-role","button");

      const a=document.createElement("a");
      a.setAttribute("class", s.btnClass || "list-item-content__button sqs-block-button-element sqs-block-button-element--medium sqs-button-element--primary");
      a.href=s.btnHref||"#";
      a.textContent=s.btnText||"Learn more";

      btnContainer.appendChild(a);
      btnWrap.appendChild(btnContainer);

      ts.appendChild(title);
      ts.appendChild(desc);
      ts.appendChild(btnWrap);

      textTrack.appendChild(ts);
    });

    textViewport.appendChild(textTrack);
    textWrap.appendChild(textViewport);

    root.innerHTML="";
    root.appendChild(stage);
    root.appendChild(dots);
    root.appendChild(textWrap);

    const anchor=section.querySelector(".user-items-list")||section.firstElementChild;
    if(!section.contains(root)){
      if(anchor && anchor.parentNode) anchor.parentNode.insertBefore(root, anchor);
      else section.appendChild(root);
    }

    let idx=0, timer=null;

    const restartRing=(btn)=>{ if(!btn) return; btn.classList.remove("is-active"); void btn.offsetWidth; btn.classList.add("is-active"); };
    const setDotActive=(newIdx)=>{ dotBtns.forEach((b,i)=>b.classList.toggle("is-active", i===newIdx)); restartRing(dotBtns[newIdx]); };
    const setTransforms=(newIdx)=>{
      track.style.transform="translate3d("+(-newIdx*100)+"%,0,0)";
      textTrack.style.transform="translate3d("+(-newIdx*100)+"%,0,0)";
    };
    const clear=()=>{ if(timer){ clearTimeout(timer); timer=null; } };
    const arm=()=>{ clear(); timer=setTimeout(()=>go((idx+1)%slides.length), dur); };

    function go(newIdx){
      idx=newIdx;
      root.classList.add("is-leaving");
      setDotActive(idx);
      setTransforms(idx);
      setTimeout(()=>root.classList.remove("is-leaving"), 420);
      arm();
    }

    dotBtns.forEach((b,i)=>b.addEventListener("click", ()=>go(i)));
    setTransforms(0);
    arm();

    root._tpKill=()=>clear();
    section.classList.add("tp-ms-ready");
  }

  function ensure(section){
    const slides=readSlides(section);
    const count=slides.length;
    const last=Number(section.dataset.tpMsCount||0);

    if(count>=1 && count!==last){
      section.dataset.tpMsCount=String(count);
      const existing=section.querySelector(".tp-mob-slider");
      if(existing && existing._tpKill) existing._tpKill();
      build(section, slides);
    }

    if(count<2){
      const tries=Number(section.dataset.tpMsTries||0);
      if(tries<14){
        section.dataset.tpMsTries=String(tries+1);
        setTimeout(()=>ensure(section), 350);
      }
    }
  }

  function scan(){ $$('section[id*="mobile-slider"]').forEach(ensure); }

  if(document.readyState==="loading") document.addEventListener("DOMContentLoaded", scan, {once:true});
  else scan();

  const mo=new MutationObserver(()=>scan());
  mo.observe(document.documentElement,{subtree:true,childList:true});
})();
</script>

12.25l22

#2. Customize

All style options in Line 04 to Line 38

12.25l22