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

Tilted Cover

A titled image component with a background element

requires interactionhover
Loading...

Installation

CLI

pnpm dlx shadcn@latest add https://animata.design/r/image/tilted-cover.json

Manual

Add to your CSS

@theme {
  --ease-slow: cubic-bezier(.405, 0, .025, 1);
  --ease-minor-spring: cubic-bezier(0.18, 0.89, 0.82, 1.04);
}

Run the following command

It will create a new file called tilted-cover.tsx inside the components/animata/image directory.

mkdir -p components/animata/image && touch components/animata/image/tilted-cover.tsx

Paste the code

Open the newly created file and paste the following code:

import type { ReactNode } from "react";
 
import { cn } from "@/lib/utils";
 
interface TiltedCoverProps extends React.HTMLAttributes<HTMLDivElement> {
  direction?: "left" | "right";
 
  /**
   * The content to be displayed on the cover
   */
  cover?: ReactNode;
 
  /**
   * Determines if the cover should tilt with the background
   */
  tiltCover?: boolean;
 
  /**
   * The content to be displayed on the background
   */
  children?: ReactNode;
 
  /**
   * The image to be displayed on the cover. Takes precedence over `children`.
   */
  image?: React.ComponentPropsWithoutRef<"img">;
}
 
export default function TiltedCover({
  children,
  direction = "left",
  tiltCover = true,
  cover,
  image,
}: TiltedCoverProps) {
  const tiltLeft = direction === "left";
  const factor = tiltLeft ? 1 : -1;
 
  return (
    // The container has height and width set to the size of the content + padding.
    <div className="flex h-64 w-52 items-center justify-center overflow-hidden">
      <div className="group/tilt relative h-52 w-40">
        {/* Background content */}
        <div
          className="border-box pointer-events-none relative h-full w-full overflow-hidden rounded-xl border bg-background transition-all duration-500 ease-slow group-hover/tilt:transform-none! dark:border-zinc-700"
          style={{
            transform: `perspective(400px) rotateY(${factor * 20}deg) scale(0.85) translateX(${-factor * 20}%)`,
          }}
        >
          {children}
          <div className="absolute inset-0 h-full w-full bg-gray-400/10 transition-all group-hover/tilt:bg-transparent" />
        </div>
 
        {/* Cover Content */}
        <div
          className={cn(
            "border-box pointer-events-none absolute inset-0 h-full w-full rounded-xl border-[6px] bg-white transition-all delay-75 duration-500 ease-slow group-hover/tilt:transform-none! group-hover/tilt:opacity-0 dark:bg-gray-800",
            {
              "group-hover/tilt:left-[200%]": tiltLeft,
              "group-hover/tilt:-left-[200%]": !tiltLeft,
            },
          )}
          style={{
            transform: tiltCover ? `perspective(400px) rotateY(${factor * 20}deg)` : undefined,
          }}
        >
          <div className="h-full w-full rounded-md object-cover">
            {image ? (
              /* Use `next/image` and remove the line below. */
              /* eslint-disable-next-line @next/next/no-img-element */
              <img
                src=""
                alt=""
                {...image}
                className={cn("h-full w-full rounded-md object-cover", image?.className)}
              />
            ) : (
              cover
            )}
          </div>
        </div>
      </div>
    </div>
  );
}

Credits

Built by hari