OiO.lk English CSS Custom carousel component – animation not working as intended
CSS

Custom carousel component – animation not working as intended


I have a custom carousel component (using React, Typescript and Tailwind) –

import React, { useState } from 'react'

interface Slide {
  content: React.ReactNode
  title: string
  description: string
}

interface CarouselProps {
  slides: Slide[]
}

const Carousel: React.FC<CarouselProps> = ({ slides }) => {
  const [currentIndex, setCurrentIndex] = useState(0)
  const [nextIndex, setNextIndex] = useState<null | number>(null)
  const [animationClass, setAnimationClass] = useState('')

  const goToPrevious = () => {
    setNextIndex(currentIndex === 0 ? slides.length - 1 : currentIndex - 1)
    setAnimationClass('slide-out-right') // Current slide exits to the right
  }

  const goToNext = () => {
    setNextIndex(currentIndex === slides.length - 1 ? 0 : currentIndex + 1)
    setAnimationClass('slide-out-left') // Current slide exits to the left
  }

  const goToSlide = (index: number) => {
    if (index > currentIndex) {
      setAnimationClass('slide-out-left')
      setTimeout(() => setNextIndex(index), 5000)
    } else if (index < currentIndex) {
      setAnimationClass('slide-out-right')
      setTimeout(() => setNextIndex(index), 5000)
    }
  }

  const handleAnimationEnd = () => {
    if (nextIndex !== null) {
      setCurrentIndex(nextIndex)
      setNextIndex(null)
      setAnimationClass(
        nextIndex > currentIndex ? 'slide-in-left' : 'slide-in-right'
      )
    }
  }

  return (
    <div className="carousel-container flex flex-col items-center">
      <div className="relative flex h-[250px] w-[400px] items-center justify-center">
        <button
          onClick={goToPrevious}
          className="absolute left-0 -translate-x-full px-4 py-2 text-lg font-bold text-gray-600"
        >
          ‹
        </button>
        <div className="carousel-content flex size-full items-center justify-center overflow-hidden rounded-lg bg-gray-100">
          <div
            className={`${animationClass} flex size-full items-center justify-center`}
            onAnimationEnd={handleAnimationEnd}
          >
            {slides[nextIndex !== null ? nextIndex : currentIndex].content}
          </div>
        </div>
        <button
          onClick={goToNext}
          className="absolute right-0 translate-x-full px-4 py-2 text-lg font-bold text-gray-600"
        >
          ›
        </button>
      </div>
      <div className="carousel-text mt-4 w-[400px] text-center">
        <h3 className="text-lg font-semibold">{slides[currentIndex].title}</h3>
        <p className="text-gray-600">{slides[currentIndex].description}</p>
      </div>
      <div className="carousel-indicators mt-2 flex space-x-1">
        {slides.map((_, index) => (
          <span
            key={index}
            onClick={() => goToSlide(index)}
            className={`block size-2 cursor-pointer rounded-full ${
              index === currentIndex ? 'bg-black' : 'bg-gray-300'
            }`}
          />
        ))}
      </div>
    </div>
  )
}

export default Carousel

I have these animations defined in my globals.css –

@keyframes slide-in-left {
  from {
    transform: translateX(100%);
  }
  to {
    transform: translateX(0);
  }
}

@keyframes slide-in-right {
  from {
    transform: translateX(-100%);
  }
  to {
    transform: translateX(0);
  }
}

@keyframes slide-out-left {
  from {
    transform: translateX(0);
  }
  to {
    transform: translateX(-100%);
  }
}

@keyframes slide-out-right {
  from {
    transform: translateX(0);
  }
  to {
    transform: translateX(100%);
  }
}

.slide-in-left {
  animation: slide-in-left 0.5s ease-in-out forwards;
}

.slide-in-right {
  animation: slide-in-right 0.5s ease-in-out forwards;
}

.slide-out-left {
  animation: slide-out-left 0.5s ease-in-out forwards;
}

.slide-out-right {
  animation: slide-out-right 0.5s ease-in-out forwards;
}

At the moment, the logic is behaving strangely and I can’t seem to figure out what I’m doing wrong. When the user navigates right, the content should slide out to the left and the new content should slide in from the right. This should work vice versa too. If I navigate left, the content slides out to the right and the new content slides in from the left.



You need to sign in to view this answers

Exit mobile version