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

Shape Shifter

A hero section with a shape-shifting component in the center

requires interactionhover
Loading...

Installation

CLI

pnpm dlx shadcn@latest add https://animata.design/r/hero/shape-shifter.json

Manual

Add to your CSS

@keyframes shape-shift {
  0% {
    width: 40px;
    height: 20px;
  }
  20% {
    width: 240px;
    height: 128px;
  }
  40% {
    width: 80px;
    height: 80px;
  }
  80% {
    width: 128px;
    height: 240px;
  }
  100% {
    width: 40px;
    height: 20px;
  }
}

Run the following command

It will create a new file called shape-shifter.tsx inside the components/animata/hero directory.

mkdir -p components/animata/hero && touch components/animata/hero/shape-shifter.tsx

Paste the code

Open the newly created file and paste the following code:

import Marquee from "@/animata/container/marquee";
import { cn } from "@/lib/utils";
 
const images: { src: string; alt: string; className?: string }[] = [
  {
    src: "https://images.unsplash.com/photo-1465804575741-338df8554e02?q=80&w=600&auto=format&fit=crop&ixlib=rb-4.0.3",
    alt: "Image 1",
  },
  {
    src: "https://images.unsplash.com/photo-1495985812444-236d6a87bdd9?w=600&auto=format&fit=crop&q=60&ixlib=rb-4.0.3",
    alt: "Image 3",
  },
  {
    src: "https://images.unsplash.com/photo-1451976426598-a7593bd6d0b2?q=80&w=600&auto=format&fit=crop&ixlib=rb-4.0.3",
    alt: "Image 2",
  },
  {
    src: "https://images.unsplash.com/photo-1479839672679-a46483c0e7c8?q=80&w=600&auto=format&fit=crop&ixlib=rb-4.0.3",
    alt: "Image 4",
  },
  {
    src: "https://images.unsplash.com/photo-1611816055460-618287c870bd?q=80&w=600&auto=format&fit=crop&ixlib=rb-4.0.3",
    alt: "Image 5",
  },
];
 
const placeholderChildren = (
  /* Marquee is optional and can be replaced with a different component like video. */
  <Marquee className="absolute inset-0 [--gap:2px]" applyMask={false} pauseOnHover>
    {images.map((image, index) => (
      /* Use `next/image` and remove the line below. */
      /* eslint-disable-next-line @next/next/no-img-element */
      <img key={`image_${index}`} {...image} alt={image.alt ?? ""} />
    ))}
  </Marquee>
);
 
export default function ShapeShifter({
  prefix = "Shape",
  suffix = "Shifter",
  className,
  containerClassName,
  children,
}: {
  className?: string;
  containerClassName?: string;
  children?: React.ReactNode;
  prefix?: React.ReactNode;
  suffix?: React.ReactNode;
}) {
  return (
    <div
      className={cn(
        "text-md group/shifter flex min-h-96 w-full min-w-fit flex-col items-center justify-center gap-3 font-bold text-foreground transition sm:flex-row sm:text-xl",
        containerClassName,
      )}
    >
      <div>{prefix}</div>
      <div
        className={cn(
          "relative animate-[shape-shift] overflow-hidden bg-black p-0 transition ease-in-out direction-alternate repeat-infinite group-hover/shifter:[animation-play-state:paused] dark:bg-white",
          className,
        )}
        // Magic number based on length of images.
        style={{ animationDuration: "8s" }}
      >
        {children ?? placeholderChildren}
      </div>
      <div>{suffix}</div>
    </div>
  );
}

Credits

Inspired by Good Loop

Images by Unsplash