Make any section to Toggle/Fixed height and then show content with show more button

Elementor CSS July 23, 2026
  1. Add a class to section or widget: zaib-collapsible
  2. Add a code or html block under it and paste this code:
<!-- ==========================================================
ZAIB Collapsible v1.1
Usage:
  1) Paste THIS block once (page or site-wide) in an Elementor HTML widget.
  2) Add class "zaib-collapsible" to any container you want collapsible.
  3) Optional per-box attributes:
       data-collapsed-height="240"   (default 200)
       data-more="See more"          (default "Show more")
       data-less="See less"          (default "Show less")
Notes:
  - Works with multiple instances.
  - Button auto-hides if content ≤ collapsed height.
  - Fade auto-matches the element’s background.
========================================================== -->
<style>
  .zaib-collapsible{
    --zaib-collapsed: 200px;  /* default; can override via data-collapsed-height or inline var */
    --zaib-fade: 72px;
    --zaib-bg: #fff;          /* set at runtime by JS */
    position: relative;
  }
  .zaib-collapsible.is-limited{
    max-height: var(--zaib-collapsed) !important;
    overflow: hidden !important;
    transition: max-height .35s ease !important;
  }
  .zaib-collapsible.is-limited::after{
    content:"";
    position:absolute; left:0; right:0; bottom:0;
    height: var(--zaib-fade);
    background: linear-gradient(to bottom, rgba(255,255,255,0), var(--zaib-bg));
    pointer-events:none;
  }
  .zaib-collapsible.is-expanded{
    max-height:none !important;
    overflow:visible !important;
  }
  .zaib-collapsible.is-expanded::after{ display:none; }
  .zaib-collapsible-btn{
    display:inline-block;
    margin-top:12px;
    padding:8px 16px;
    background:#222; color:#fff;
    border:0; border-radius:6px;
    font-size:14px; line-height:1;
    cursor:pointer;
    transition: background .2s ease;
  }
  .zaib-collapsible-btn:hover{ background:#000; }
  .zaib-collapsible-btn-wrap{ text-align:center; }
</style>
<script>
(function(){
  const SEL = '.zaib-collapsible';
  function measureAndWire(el){
    if(!el || el.dataset.zaibProcessed) return;
    // Read options
    const collapsed = parseInt(el.getAttribute('data-collapsed-height') || '200', 10);
    const labelMore = el.getAttribute('data-more') || 'Show more';
    const labelLess = el.getAttribute('data-less') || 'Show less';
    // Apply CSS var
    el.style.setProperty('--zaib-collapsed', collapsed + 'px');
    // Set fade bg to computed background (fallback to #fff)
    try{
      let bg = getComputedStyle(el).backgroundColor;
      if(!bg || bg === 'rgba(0, 0, 0, 0)') {
        // climb up until we find a non-transparent bg
        let p = el.parentElement;
        while(p && (!bg || bg === 'rgba(0, 0, 0, 0)')){
          bg = getComputedStyle(p).backgroundColor;
          p = p.parentElement;
        }
      }
      el.style.setProperty('--zaib-bg', bg || '#fff');
    }catch(e){}
    // If short, skip and don't add button
    if(el.scrollHeight <= collapsed + 10){
      el.dataset.zaibProcessed = '1';
      return;
    }
    // Limit
    el.classList.add('is-limited');
    // Button
    const wrap = document.createElement('div');
    wrap.className = 'zaib-collapsible-btn-wrap';
    const btn = document.createElement('button');
    btn.type = 'button';
    btn.className = 'zaib-collapsible-btn';
    btn.textContent = labelMore;
    // a11y attributes
    if(!el.id){ el.id = 'zaibcol-' + Math.random().toString(36).slice(2,9); }
    btn.setAttribute('aria-controls', el.id);
    btn.setAttribute('aria-expanded', 'false');
    wrap.appendChild(btn);
    el.insertAdjacentElement('afterend', wrap);
    btn.addEventListener('click', function(){
      const expanded = el.classList.toggle('is-expanded');
      if(expanded){
        el.classList.remove('is-limited');
        btn.textContent = labelLess;
        btn.setAttribute('aria-expanded', 'true');
      }else{
        el.classList.add('is-limited');
        btn.textContent = labelMore;
        btn.setAttribute('aria-expanded', 'false');
        const r = el.getBoundingClientRect();
        if(r.top < 0){ window.scrollBy({ top: r.top - 20, behavior: 'smooth' }); }
      }
    });
    el.dataset.zaibProcessed = '1';
  }
  function initAll(){
    document.querySelectorAll(SEL).forEach(measureAndWire);
  }
  // Run on DOM ready, window load, and after a small delay (Elementor rendering)
  if(document.readyState === 'loading'){
    document.addEventListener('DOMContentLoaded', initAll);
  } else {
    initAll();
  }
  window.addEventListener('load', function(){ setTimeout(initAll, 50); });
  // MutationObserver: handle widgets that render after initial load
  const mo = new MutationObserver(function(muts){
    for(const m of muts){
      if(m.addedNodes && m.addedNodes.length){
        // If any added subtree contains a collapsible, init it
        if(m.target && (m.target.matches && m.target.matches(SEL) || m.target.querySelector && m.target.querySelector(SEL))){
          initAll();
        }
        m.addedNodes.forEach(n=>{
          if(n.nodeType===1 && (n.matches(SEL) || n.querySelector && n.querySelector(SEL))){
            initAll();
          }
        });
      }
    }
  });
  mo.observe(document.documentElement, { childList: true, subtree: true });
})();
</script>