🚀

Update available

We just released a new resource or update, refresh the Vault to access the latest version.

Cancel

Refresh now

Harri

Profile Picture

Harri

Lemke

Logo Wall Cycle

Documentation

Webflow

Code

Setup: External Scripts

HTML

Copy
<script src="https://cdn.jsdelivr.net/npm/gsap@3.15/dist/gsap.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.15/dist/ScrollTrigger.min.js"></script>

Step 1: Add HTML

HTML

Copy
<div data-logo-wall-shuffle="false" data-logo-wall-cycle-init="" class="logo-wall">
  <div class="logo-wall__collection">
    <div data-logo-wall-list="" class="logo-wall__list">
      <div data-logo-wall-item="" class="logo-wall__item">
        <div data-logo-wall-target-parent="" class="logo-wall__logo">
          <div class="logo-wall__logo-before"></div>
          <div data-logo-wall-target="" class="logo-wall__logo-target">
            <img src="https://cdn.prod.website-files.com/68836e3f51ac98fec14ceed2/688370ea9d37fbceb3be49cb_logo-webflow.svg" loading="lazy" width="100" alt="" class="logo-wall__logo-img">
          </div>
        </div>
      </div>
      <div data-logo-wall-item="" class="logo-wall__item">
        <div data-logo-wall-target-parent="" class="logo-wall__logo">
          <div class="logo-wall__logo-before"></div>
          <div data-logo-wall-target="" class="logo-wall__logo-target">
            <img src="https://cdn.prod.website-files.com/68836e3f51ac98fec14ceed2/688370ea48d4fb0c708dd1dc_logo-microsoft.svg" loading="lazy" width="100" alt="" class="logo-wall__logo-img">
          </div>
        </div>
      </div>
      <div data-logo-wall-item="" class="logo-wall__item">
        <div data-logo-wall-target-parent="" class="logo-wall__logo">
          <div class="logo-wall__logo-before"></div>
          <div data-logo-wall-target="" class="logo-wall__logo-target">
            <img src="https://cdn.prod.website-files.com/68836e3f51ac98fec14ceed2/688370ea9ba384ff47fa5d51_logo-asana.svg" loading="lazy" width="100" alt="" class="logo-wall__logo-img">
          </div>
        </div>
      </div>
      <div data-logo-wall-item="" class="logo-wall__item">
        <div data-logo-wall-target-parent="" class="logo-wall__logo">
          <div class="logo-wall__logo-before"></div>
          <div data-logo-wall-target="" class="logo-wall__logo-target">
            <img src="https://cdn.prod.website-files.com/68836e3f51ac98fec14ceed2/688370eaec918fbd4a0acc12_logo-snapchat.svg" loading="lazy" width="100" alt="" class="logo-wall__logo-img">
          </div>
        </div>
      </div>
      <div data-logo-wall-item="" class="logo-wall__item">
        <div data-logo-wall-target-parent="" class="logo-wall__logo">
          <div class="logo-wall__logo-before"></div>
          <div data-logo-wall-target="" class="logo-wall__logo-target">
            <img src="https://cdn.prod.website-files.com/68836e3f51ac98fec14ceed2/688370ea155a551c08692a03_logo-google.svg" loading="lazy" width="100" alt="" class="logo-wall__logo-img">
          </div>
        </div>
      </div>
      <div data-logo-wall-item="" class="logo-wall__item">
        <div data-logo-wall-target-parent="" class="logo-wall__logo">
          <div class="logo-wall__logo-before"></div>
          <div data-logo-wall-target="" class="logo-wall__logo-target">
            <img src="https://cdn.prod.website-files.com/68836e3f51ac98fec14ceed2/688370eafdf2b295d65f9450_logo-bluesky.svg" loading="lazy" width="100" alt="" class="logo-wall__logo-img">
          </div>
        </div>
      </div>
      <div data-logo-wall-item="" class="logo-wall__item">
        <div data-logo-wall-target-parent="" class="logo-wall__logo">
          <div class="logo-wall__logo-before"></div>
          <div data-logo-wall-target="" class="logo-wall__logo-target">
            <img src="https://cdn.prod.website-files.com/68836e3f51ac98fec14ceed2/688370ea68a433ee5808ed90_logo-codepen.svg" loading="lazy" width="100" alt="" class="logo-wall__logo-img">
          </div>
        </div>
      </div>
      <div data-logo-wall-item="" class="logo-wall__item">
        <div data-logo-wall-target-parent="" class="logo-wall__logo">
          <div class="logo-wall__logo-before"></div>
          <div data-logo-wall-target="" class="logo-wall__logo-target">
            <img src="https://cdn.prod.website-files.com/68836e3f51ac98fec14ceed2/688370ea2ebc0415055d04f3_logo-linkedin.svg" loading="lazy" width="100" alt="" class="logo-wall__logo-img">
          </div>
        </div>
      </div>
      <div data-logo-wall-item="" class="logo-wall__item">
        <div data-logo-wall-target-parent="" class="logo-wall__logo">
          <div class="logo-wall__logo-before"></div>
          <div data-logo-wall-target="" class="logo-wall__logo-target">
            <img src="https://cdn.prod.website-files.com/68836e3f51ac98fec14ceed2/688370ea7699561e6f9f008f_logo-android.svg" loading="lazy" width="100" alt="" class="logo-wall__logo-img">
          </div>
        </div>
      </div>
      <div data-logo-wall-item="" class="logo-wall__item">
        <div data-logo-wall-target-parent="" class="logo-wall__logo">
          <div class="logo-wall__logo-before"></div>
          <div data-logo-wall-target="" class="logo-wall__logo-target">
            <img src="https://cdn.prod.website-files.com/68836e3f51ac98fec14ceed2/688370ea753f2afe2f6b036f_logo-apple.svg" loading="lazy" width="100" alt="" class="logo-wall__logo-img">
          </div>
        </div>
      </div>
      <div data-logo-wall-item="" class="logo-wall__item">
        <div data-logo-wall-target-parent="" class="logo-wall__logo">
          <div class="logo-wall__logo-before"></div>
          <div data-logo-wall-target="" class="logo-wall__logo-target">
            <img src="https://cdn.prod.website-files.com/68836e3f51ac98fec14ceed2/688370eabec1e0c00348b5ed_logo-twitter.svg" loading="lazy" width="100" alt="" class="logo-wall__logo-img">
          </div>
        </div>
      </div>
      <div data-logo-wall-item="" class="logo-wall__item">
        <div data-logo-wall-target-parent="" class="logo-wall__logo">
          <div class="logo-wall__logo-before"></div>
          <div data-logo-wall-target="" class="logo-wall__logo-target">
            <img src="https://cdn.prod.website-files.com/68836e3f51ac98fec14ceed2/688370ea0e0e1dc81a9b5799_logo-osmo.svg" loading="lazy" width="100" alt="" class="logo-wall__logo-img">
          </div>
        </div>
      </div>
      <div data-logo-wall-item="" class="logo-wall__item">
        <div data-logo-wall-target-parent="" class="logo-wall__logo">
          <div class="logo-wall__logo-before"></div>
          <div data-logo-wall-target="" class="logo-wall__logo-target">
            <img src="https://cdn.prod.website-files.com/68836e3f51ac98fec14ceed2/688370ea36c91584afe43e2d_logo-medium.svg" loading="lazy" width="100" alt="" class="logo-wall__logo-img">
          </div>
        </div>
      </div>
      <div data-logo-wall-item="" class="logo-wall__item">
        <div data-logo-wall-target-parent="" class="logo-wall__logo">
          <div class="logo-wall__logo-before"></div>
          <div data-logo-wall-target="" class="logo-wall__logo-target">
            <img src="https://cdn.prod.website-files.com/68836e3f51ac98fec14ceed2/688370ea87b05cdce0387084_logo-eventbrite.svg" loading="lazy" width="100" alt="" class="logo-wall__logo-img">
          </div>
        </div>
      </div>
      <div data-logo-wall-item="" class="logo-wall__item">
        <div data-logo-wall-target-parent="" class="logo-wall__logo">
          <div class="logo-wall__logo-before"></div>
          <div data-logo-wall-target="" class="logo-wall__logo-target">
            <img src="https://cdn.prod.website-files.com/68836e3f51ac98fec14ceed2/688370eaf4465d763c2f9b2a_logo-behance.svg" loading="lazy" width="100" alt="" class="logo-wall__logo-img">
          </div>
        </div>
      </div>
      <div data-logo-wall-item="" class="logo-wall__item">
        <div data-logo-wall-target-parent="" class="logo-wall__logo">
          <div class="logo-wall__logo-before"></div>
          <div data-logo-wall-target="" class="logo-wall__logo-target">
            <img src="https://cdn.prod.website-files.com/68836e3f51ac98fec14ceed2/688370eaec1d445957d7e3a1_logo-chatgpt.svg" loading="lazy" width="100" alt="" class="logo-wall__logo-img">
          </div>
        </div>
      </div>
    </div>
  </div>
</div>

Step 2: Add CSS

CSS

Copy
.logo-wall {
  display: flex;
  justify-content: center;
  width: 100%;
}

.logo-wall__collection {
  width: 100%;
}

.logo-wall__list {
  display: flex;
  flex-flow: wrap;
}

.logo-wall__item {
  width: 25%;
  position: relative;
}

[data-logo-wall-list] [data-logo-wall-item]:nth-child(n+9) {
  display: none;
}

.logo-wall__logo {
  display: flex;
  justify-content: center;
  align-items: center;
  position: relative;
}

.logo-wall__logo-before {
  padding-top: 66.66%;
}

.logo-wall__logo-target {
  justify-content: center;
  align-items: center;
  width: 66.66%;
  height: 40%;
  display: flex;
  position: absolute;
}

.logo-wall__logo-img {
  width: 100%;
  height: 100%;
  max-height: 100%;
}

@media screen and (max-width: 991px) {
  .logo-wall__item {
    width: 33.333%;
  }

  [data-logo-wall-list] [data-logo-wall-item]:nth-child(n+7) {
    display: none;
  }
}

Step 2: Add Javascript

Step 3: Add Javascript

Javascript

Copy
function initLogoWallCycle() {
  const loopDelay = 1.5;   // Loop Duration
  const duration  = 0.9;   // Animation Duration

  document.querySelectorAll('[data-logo-wall-cycle-init]').forEach(root => {
    const list   = root.querySelector('[data-logo-wall-list]');
    const items  = Array.from(list.querySelectorAll('[data-logo-wall-item]'));

    const shuffleFront = root.getAttribute('data-logo-wall-shuffle') !== 'false';
    const originalTargets = items
      .map(item => item.querySelector('[data-logo-wall-target]'))
      .filter(Boolean);

    let visibleItems   = [];
    let visibleCount   = 0;
    let pool           = [];
    let pattern        = [];
    let patternIndex   = 0;
    let tl;

    function isVisible(el) {
      return window.getComputedStyle(el).display !== 'none';
    }

    function shuffleArray(arr) {
      const a = arr.slice();
      for (let i = a.length - 1; i > 0; i--) {
        const j = Math.floor(Math.random() * (i + 1));
        [a[i], a[j]] = [a[j], a[i]];
      }
      return a;
    }

    function setup() {
      if (tl) {
        tl.kill();
      }
      visibleItems = items.filter(isVisible);
      visibleCount = visibleItems.length;

      pattern = shuffleArray(
        Array.from({ length: visibleCount }, (_, i) => i)
      );
      patternIndex = 0;

      // remove all injected targets
      items.forEach(item => {
        item.querySelectorAll('[data-logo-wall-target]').forEach(old => old.remove());
      });

      pool = originalTargets.map(n => n.cloneNode(true));

      let front, rest;
      if (shuffleFront) {
        const shuffledAll = shuffleArray(pool);
        front = shuffledAll.slice(0, visibleCount);
        rest  = shuffleArray(shuffledAll.slice(visibleCount));
      } else {
        front = pool.slice(0, visibleCount);
        rest  = shuffleArray(pool.slice(visibleCount));
      }
      pool = front.concat(rest);

      for (let i = 0; i < visibleCount; i++) {
        const parent =
          visibleItems[i].querySelector('[data-logo-wall-target-parent]') ||
          visibleItems[i];
        parent.appendChild(pool.shift());
      }

      tl = gsap.timeline({ repeat: -1, repeatDelay: loopDelay });
      tl.call(swapNext);
      tl.play();
    }

    function swapNext() {
      const nowCount = items.filter(isVisible).length;
      if (nowCount !== visibleCount) {
        setup();
        return;
      }
      if (!pool.length) return;

      const idx = pattern[patternIndex % visibleCount];
      patternIndex++;

      const container = visibleItems[idx];
      const parent =
        container.querySelector('[data-logo-wall-target-parent]') ||
        container.querySelector('*:has(> [data-logo-wall-target])') ||
        container;
      const existing = parent.querySelectorAll('[data-logo-wall-target]');
      if (existing.length > 1) return;

      const current  = parent.querySelector('[data-logo-wall-target]');
      const incoming = pool.shift();

      gsap.set(incoming, { yPercent: 50, autoAlpha: 0 });
      parent.appendChild(incoming);

      if (current) {
        gsap.to(current, {
          yPercent: -50,
          autoAlpha: 0,
          duration,
          ease: "expo.inOut",
          onComplete: () => {
            current.remove();
            pool.push(current);
          }
        });
      }

      gsap.to(incoming, {
        yPercent: 0,
        autoAlpha: 1,
        duration,
        delay: 0.1,
        ease: "expo.inOut"
      });
    }

    setup();

    ScrollTrigger.create({
      trigger: root,
      start: 'top bottom',
      end: 'bottom top',
      onEnter:     () => tl.play(),
      onLeave:     () => tl.pause(),
      onEnterBack: () => tl.play(),
      onLeaveBack: () => tl.pause()
    });

    document.addEventListener('visibilitychange', () =>
      document.hidden ? tl.pause() : tl.play()
    );
  });
}

// Initialize Logo Wall Cycle
document.addEventListener('DOMContentLoaded', () => {
  initLogoWallCycle();
});

Implementation

Container

Add the [data-logo-wall-cycle-init] attribute to the outermost wrapper (the “logo wall container”). This will initialize a single logo wall animation instance.

You can configure shuffling behavior with the optional [data-logo-wall-shuffle] attribute. When this is enabled the first visible logo's will be shuffeled too.

List

Apply [data-logo-wall-list] to the element that wraps all logo items.

Item

Each logo entry requires [data-logo-wall-item]. This acts as a placeholder for rotating logos.

We use CSS to hide the extra logos, this can be different on every viewport. The script will look for display: none; to decide what logos are not included.

/* Desktop: Show only first 8 */
[data-logo-wall-list] > [data-logo-wall-item]:nth-child(n+9) {
  display: none;
}

/* Tablet/mobile: Show only first 6 */
@media (max-width: 768px) {
  [data-logo-wall-list] > [data-logo-wall-item]:nth-child(n+7) {
    display: none;
  }
}
Copy

Target & Target Parent

Inside each item, add a [data-logo-wall-target] element. This is the element that gets animated in/out during swaps.

You can wrap this in a parent element marked with [data-logo-wall-target-parent] if you want more control over placement. When the this attribute is not added the next logo will be placed in the [data-logo-wall-item] element.

Customizing the Animation

This example uses a slide-and-fade animation to cycle logos in and out. You can easily replace it with any animation style that better suits your project.

Live preview

Osmo Robot AI

Copy context for AI

Beta

Webflow

HTML/CSS/JS

Save video

Copy share link

Resource details

  • Published

    July 27, 2025

  • Category

    Sections & Layouts

  • Popularity

    3.5K visitors

  • Need help?

    Join Slack

Logos
List
Animation
Looping
Cycle
Transition
Dennis SnellenbergDennis Snellenberg

Creator Credits

We always strive to credit creators as accurately as possible. While similar concepts might appear online, we aim to provide proper and respectful attribution.

s