NEW
shadcn registry is live·
shadcn registry is live·
shadcn registry is live·
shadcn registry is live·
shadcn registry is live·
shadcn registry is live·
shadcn registry is live·
shadcn registry is live·
shadcn registry is live·
shadcn registry is live·
shadcn registry is live·
shadcn registry is live·
Learn more
Skip to content
Docs

Split Text

A text effect where the text splits into two when hovered

requires interactionhover
Loading...

Installation

CLI

pnpm dlx shadcn@latest add https://animata.design/r/text/split-text.json

Manual

Run the following command

It will create a new file split-text.tsx inside the components/animata/text directory.

mkdir -p components/animata/text && touch components/animata/text/split-text.tsx

Paste the code

Open the newly created file and paste the following code:

import { useRef, useState } from "react";
 
import { cn } from "@/lib/utils";
 
export default function SplitText({
  text = "ANIMATA",
  className,
}: {
  text: string;
  className?: string;
}) {
  const [activeIndex, setIndex] = useState<number>();
  const timer = useRef<NodeJS.Timeout>(undefined);
 
  const letterClassName =
    "inline h-1/2 select-none overflow-y-hidden leading-none transition duration-300 ease-out whitespace-pre";
 
  return (
    <div
      className={cn(
        "relative mx-auto text-4xl font-black uppercase text-yellow-500 md:text-5xl lg:text-9xl",
        className,
      )}
    >
      {/** add hidden text so that we maintain the size for any text */}
      <div className="invisible leading-none">{text}</div>
      <div className="absolute top-0 flex h-full">
        {text.split("").map((letter, index) => (
          <div
            onMouseEnter={() => {
              if (timer.current) {
                clearTimeout(timer.current);
              }
              setIndex(index);
            }}
            onMouseLeave={() => {
              timer.current = setTimeout(() => {
                setIndex(undefined);
              });
            }}
            key={`${letter}-${index}`}
            className="relative inline-flex h-full flex-col leading-none"
            aria-hidden
          >
            {/** top half */}
            <span
              className={cn(letterClassName, {
                "-translate-y-5": index === activeIndex,
                "-translate-y-3":
                  activeIndex !== undefined &&
                  (index === activeIndex - 1 || index === activeIndex + 1),
                "-translate-y-1":
                  activeIndex !== undefined &&
                  (index === activeIndex - 2 || index === activeIndex + 2),
              })}
            >
              {letter}
            </span>
 
            {/** bottom half */}
            <span
              className={cn(letterClassName, {
                "translate-y-5": index === activeIndex,
                "translate-y-3":
                  activeIndex !== undefined &&
                  (index === activeIndex - 1 || index === activeIndex + 1),
                "translate-y-1":
                  activeIndex !== undefined &&
                  (index === activeIndex - 2 || index === activeIndex + 2),
              })}
            >
              <span className="absolute -translate-y-1/2 leading-none">{letter}</span>
            </span>
          </div>
        ))}
      </div>
    </div>
  );
}

Credits

Built by hari