JSFiddle - React, Tailwind, and code Playground

by dumptyd

HTML

<div class="item-wrapper"></div>
<button id="next">Next</button>

CSS

body {
  font-family: 'Ubuntu', 'Arial';
  text-align: center;
}

.item-wrapper {
  position: relative;
  height: 300px; width: 150px;
  border: 1px solid #333;
  margin: 50px auto;
  overflow: hidden;
}

.item {
  position: absolute;
  height: 100px; width: 100%;
  background-color: orange;
  display: flex; align-items: center; justify-content: center;
  border: 1px solid #ccc;
  box-sizing: border-box;
}
.transition { transition: .25s all ease; }

JavaScript

const $ = document.querySelector.bind(document);

class ShitLooper {
	constructor({
  	itemsCount = 7, itemHeight = 100,
    prevSelector = '#prev', nextSelector = '#next',
    parentSelector = '.item-wrapper'
  }) {
  	[this.itemsCount, this.itemHeight] = [itemsCount, itemHeight];
    const wrapper = $(parentSelector);
    this.itemEls = Array(itemsCount).fill(true).map((item, idx) => {
      const itemEl = document.createElement('DIV');
      const top = idx * itemHeight;
      [itemEl.attrtop, itemEl.style.top] = [top, `${top}px`];
			itemEl.classList.add('item');
      itemEl.textContent = `Item ${idx + 1}`;
      wrapper.appendChild(itemEl);
      return itemEl;
    });
    this.inTransition = false;
    this.attachHandler(nextSelector, 1);
  }
  attachHandler(selector) {
		$(selector).addEventListener('click', () => {
      if (this.inTransition) return;
			this.inTransition = true;

			this.itemEls.forEach(itemEl => {
        itemEl.classList.add('transition');
        itemEl.attrtop -= this.itemHeight;
        itemEl.style.top = `${itemEl.attrtop}px`;
      });

			const el = this.itemEls.shift();
      this.itemEls.push(el);
  
  		el.attrtop = (this.itemEls.length - 1) * this.itemHeight;
      el.ontransitionend = () => {
        el.classList.remove('transition');
        el.style.top = `${el.attrtop}px`;
        el.ontransitionend = null;
        this.inTransition = false;
      };
    });  	
  }
}

new ShitLooper({ itemsCount: 10 });