✨ Introducing NextLaunch — Premium templates designed to help you build stunning landing pages in minutes.

Slider

This is a Slider component.

Loremipsum

Brandlogo

Logoipsum

Loremipsum

Brandlogo

Logoipsum

Loremipsum

Brandlogo

Logoipsum

Installation

1. Dependencies

npm install clsx tailwind-merge

2. Paste inside @/lib/utils.ts

import { clsx } from "clsx";
import { twMerge } from "tailwind-merge";

export function cn(...inputs: Parameters<typeof clsx>) {
  return twMerge(clsx(...inputs));
}

3. Copy Slider Code

"use client";

import { cn } from "@/lib/utils";
import React, { useEffect, useState } from "react";

interface SliderProps {
  children: React.ReactNode;
  width?: string;
  duration?: number;
  toRight?: boolean;
  pauseOnHover?: boolean;
}

/**
 * Slider component that creates a truly infinite horizontal scrolling effect for its children.
 * @param {React.ReactNode} children - The content to be displayed inside the slider.
 * @param {string} width - The width of each slide. Default is "200px".
 * @param {number} duration - The duration of the animation in seconds. Default is 40 seconds.
 * @param {boolean} toRight - Direction of the animation. If true, slides to the right. Default is false (slides to the left).
 * @param {boolean} pauseOnHover - If true, pauses the animation on hover. Default is false.
 * @returns {JSX.Element} The Slider component.
 * @example
 * <Slider width="300px" duration={60} toRight={false} pauseOnHover={true}>
 *  <h2 className="sm:text-2xl text-lg font-semibold text-foreground w-32">Slide 1</h2>
 *  <h2 className="sm:text-2xl text-lg font-semibold text-foreground w-32">Slide 2</h2>
 *  <h2 className="sm:text-2xl text-lg font-semibold text-foreground w-32">Slide 3</h2>
 * </Slider>
 */
const Slider = ({
  children,
  width = "200px",
  duration = 40,
  toRight = false,
  pauseOnHover = false,
}: SliderProps) => {
  const [idNanoid, setIdNanoid] = useState<string>("");

  useEffect(() => {
    setIdNanoid(Math.random().toString(36).substring(2, 12));
  }, []);

  useEffect(() => {
    const totalTranslateX = `calc(${toRight ? "" : "-"}${width} * ${React.Children.count(children)})`;
    const style = document.createElement("style");
    style.type = "text/css";
    style.innerHTML = `
      @keyframes slider_animation_${idNanoid} {
        0% { transform: translateX(0); }
        100% { transform: translateX(${totalTranslateX}); }
      }
    `;
    document.head.appendChild(style);

    return () => {
      document.head.removeChild(style);
    };
  }, [toRight, width, children, idNanoid]);

  const handleMouseEnter = () => {
    if (!pauseOnHover) return;
    const sliderElement = document.getElementById(`slider_${idNanoid}`);
    if (sliderElement) sliderElement.style.animationPlayState = "paused";
  };

  const handleMouseLeave = () => {
    if (!pauseOnHover) return;
    const sliderElement = document.getElementById(`slider_${idNanoid}`);
    if (sliderElement) sliderElement.style.animationPlayState = "running";
  };

  return (
    <div style={{ position: "relative", width: "100%", overflow: "hidden" }}>
      <div
        style={{
          display: "flex",
          animation: `slider_animation_${idNanoid} ${duration}s linear infinite`,
          width: `calc(${width} * ${React.Children.count(children) * 3})`,
        }}
        className="space-x-10"
        id={`slider_${idNanoid}`}
        onMouseEnter={handleMouseEnter}
        onMouseLeave={handleMouseLeave}
      >
        {Array(3)
          .fill(children)
          .flat()
          .map((child, i) => (
            <React.Fragment key={i}>{child}</React.Fragment>
          ))}
      </div>
    </div>
  );
};

interface SlideProps {
  children: React.ReactNode;
  width?: string;
  className?: string;
}

/**
 * Slide component to be used inside the Slider component.
 * It accepts children and an optional width prop.
 * @param {React.ReactNode} children - The content to be displayed inside the slide.
 * @param {string} width - The width of the slide. Default is "200px".
 * @param {string} className - Additional class names for styling.
 * @returns {JSX.Element} The Slide component.
 */
const Slide: React.FC<SlideProps> = ({ children, width = "200px", className }) => {
  return (
    <div style={{ width, display: "flex", alignItems: "center", justifyContent: "center" }} className={cn(className)}>
      {children}
    </div>
  );
};

Slider.Slide = Slide;

export { Slider };

Copy Slider Code

Slider Props

NameTypeRequiredDefaultDescription
childrenReact.ReactNodeYesundefinedThe content of the slider.
widthstringNo"200px"The width of the slider.
durationnumberNo4000Duration of each slide in milliseconds.
toRightbooleanNofalseDirection of the slide transition.
pauseOnHoverbooleanNofalsePause the slider on hover.

Slide Props

NameTypeRequiredDefaultDescription
childrenReact.ReactNodeYesundefinedThe content of the slide.
widthstringNo"200px"The width of the slide.
classNamestringNoundefinedAdditional class names for styling.