Docs

Swap Text

A component that swaps text on click or hover.

requires interactionhoverclick

Installation

Update tailwind.config.js

theme: {
    extend: {
        colors: {
        foreground: "hsl(var(--foreground))",
     },
       transitionTimingFunction: {
        slow: "cubic-bezier(.405, 0, .025, 1)",
        "minor-spring": "cubic-bezier(0.18,0.89,0.82,1.04)",
     }
    },
  },

Run the following command

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

touch components/animata/text/swap-text.tsx

Paste the code

Open the newly created file and paste the following code:

import { useState } from "react";
 
import { cn } from "@/lib/utils";
 
interface SwapTextProps extends React.ComponentPropsWithoutRef<"div"> {
  /**
   * The initial text to display.
   */
  initialText: string;
 
  /**
   * The final text to display.
   */
  finalText: string;
 
  /**
   * Whether the component should toggle on hover as well as click.
   */
  supportsHover?: boolean;
 
  /**
   * The class name for the text.
   */
  textClassName?: string;
 
  /**
   * The class name for the initial text.
   */
  initialTextClassName?: string;
 
  /**
   * The class name for the final text.
   */
  finalTextClassName?: string;
 
  /**
   * Whether to disable the click interaction.
   */
  disableClick?: boolean;
}
 
export default function SwapText({
  initialText,
  finalText,
  className,
  supportsHover = true,
  textClassName,
  initialTextClassName,
  finalTextClassName,
  disableClick,
  // The rest of the props are passed to the container div.
  ...props
}: SwapTextProps) {
  const [active, setActive] = useState(false);
  const common = "block transition-all duration-1000 ease-slow";
 
  const longWord = finalText.length > initialText.length ? finalText : null;
 
  return (
    <div {...props} className={cn("relative overflow-hidden text-foreground", className)}>
      <div
        className={cn("group cursor-pointer select-none text-3xl font-bold", textClassName)}
        onClick={() => !disableClick && setActive((current) => !current)}
      >
        <span
          className={cn(common, initialTextClassName, {
            "flex flex-col": true,
            "-translate-y-full": active,
            "group-hover:-translate-y-full": supportsHover,
          })}
        >
          {initialText}
          {
            /* Trick to make sure it can always fit all available words after transition as the second word is set to absolute*/
            Boolean(longWord?.length) && <span className="invisible h-0">{longWord}</span>
          }
        </span>
        <span
          className={cn(`${common} absolute top-full`, finalTextClassName, {
            "-translate-y-full": active,
            "group-hover:-translate-y-full": supportsHover,
          })}
        >
          {finalText}
        </span>
      </div>
    </div>
  );
}

Credits

Built by hari