Simple Carousel using Javascript scrolling

December 10, 2020  •   3 min read


There are various ways to implement carousel which give you more control on the animation. I discovered a really simple way to implement carousel by triggering scrolling function and its perfect for simple use cases.
We'll maintain the index of component/image in view to bring next element into view and we can disable next and previous buttons on edges. Onn click of any of those buttons we'll take that element and call this function. inline parameter is for horizontal scrolling. There's another parameter block which you can experiment with.

element.scrollIntoView({behavior: "smooth", inline: "center", block: "nearest"});
Note: Important parameter here is smooth behavior which makes this cool animation possible.
Make a container div with scroll auto, display flex and add some elements to it. When you are satisfied with your normal scrolling design, set overflow to hidden. This is important cause we'll do that on button clicks and of course we don't involuntary mouse scrolls.
carousel

.carousel-container {
  display: flex;
  height: 300px;
  width: 500px;
  overflow: hidden;
}
Then on next or previous click, get the DOM element and call scrollIntoView on the element with right parameters according to your carousel alignment.

const nextClicked = () => {
  if (activeInd < (totalItems - 1)) {
    const nextInd = activeInd + 1
    
    // get the element and call scrollIntoView
    containerRef.current.children[nextInd].scrollIntoView({ behavior: "smooth", inline: "center", block: "nearest" });
    setActiveInd(nextInd)
  }
}
I've used ref on the container and then accessed its children using the index. In Angular it can be achieved using @ViewChildren.
Here's the full code of this simple carousel component.

const CarouselComp = () => {
  const [activeInd, setActiveInd] = useState(0)
  const containerRef = useRef()
  const totalItems = 5

  const nextClicked = () => {
    if (activeInd < (totalItems - 1)) {
      const nextInd = activeInd + 1
      containerRef.current.children[nextInd].scrollIntoView({ behavior: "smooth", inline: "center", block: "nearest" })
      setActiveInd(nextInd)
    }
  }

  const previousClicked = () => {
    if (activeInd > 0) {
      const nextInd = activeInd - 1
      containerRef.current.children[nextInd].scrollIntoView({ behavior: "smooth", inline: "center", block: "nearest" })
      setActiveInd(nextInd)
    }
  }

  return (
    <div className='carousel-comp'>
      <div className='carousel-container' ref={containerRef}>
        <div className='carousel-item'>0</div>
        <div className='carousel-item'>1</div>
        <div className='carousel-item'>2</div>
        <div className='carousel-item'>3</div>
        <div className='carousel-item'>4</div>
      </div>

      <div className='carousel-actions'>
        <i className="ph-caret-circle-left" onClick={previousClicked}></i>
        <i className="ph-caret-circle-right" onClick={nextClicked}></i>
      </div>
    </div>
  )
}