Hover Reveal Details Card

PreviousNext

Animated card with gesture animations, Reveals hidden content and scale main image on hover.

Docs
systaliko-uiui

Preview

Loading preview…
registry/cards/card-hover-reveal/index.tsx
'use client';

import * as React from 'react';

import { cn } from '@/lib/utils';

interface CardHoverRevealContextValue {
  isHovered: boolean;
  setIsHovered: React.Dispatch<React.SetStateAction<boolean>>;
}
const CardHoverRevealContext = React.createContext<CardHoverRevealContextValue>(
  {} as CardHoverRevealContextValue,
);
const useCardHoverRevealContext = () => {
  const context = React.useContext(CardHoverRevealContext);
  if (!context) {
    throw new Error(
      'useCardHoverRevealContext must be used within a CardHoverRevealProvider',
    );
  }
  return context;
};
const CardHoverReveal = React.forwardRef<
  HTMLDivElement,
  React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => {
  const [isHovered, setIsHovered] = React.useState<boolean>(false);

  const handleMouseEnter = () => setIsHovered(true);
  const handleMouseLeave = () => setIsHovered(false);

  return (
    <CardHoverRevealContext.Provider
      value={{
        isHovered,
        setIsHovered,
      }}
    >
      <div
        ref={ref}
        className={cn('relative overflow-hidden', className)}
        onMouseEnter={handleMouseEnter}
        onMouseLeave={handleMouseLeave}
        {...props}
      />
    </CardHoverRevealContext.Provider>
  );
});
CardHoverReveal.displayName = 'CardHoverReveal';

interface CardHoverRevealMainProps {
  initialScale?: number;
  hoverScale?: number;
}
const CardHoverRevealMain = React.forwardRef<
  HTMLDivElement,
  React.HTMLAttributes<HTMLDivElement> & CardHoverRevealMainProps
>(({ className, initialScale = 1, hoverScale = 1.05, ...props }, ref) => {
  const { isHovered } = useCardHoverRevealContext();
  return (
    <div
      ref={ref}
      className={cn('size-full transition-transform duration-300 ', className)}
      style={
        isHovered
          ? { transform: `scale(${hoverScale})`, ...props.style }
          : { transform: `scale(${initialScale})`, ...props.style }
      }
      {...props}
    />
  );
});
CardHoverRevealMain.displayName = 'CardHoverRevealMain';

const CardHoverRevealContent = React.forwardRef<
  HTMLDivElement,
  React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => {
  const { isHovered } = useCardHoverRevealContext();
  return (
    <div
      ref={ref}
      className={cn(
        'absolute inset-[auto_1.5rem_1.5rem] p-6 backdrop-blur-lg transition-all duration-500 ease-in-out',
        className,
      )}
      style={
        isHovered
          ? { translate: '0%', opacity: 1, ...props.style }
          : { translate: '0% 120%', opacity: 0, ...props.style }
      }
      {...props}
    />
  );
});
CardHoverRevealContent.displayName = 'CardHoverRevealContent';

export { CardHoverReveal, CardHoverRevealMain, CardHoverRevealContent };

Installation

npx shadcn@latest add @systaliko-ui/card-hover-reveal

Usage

import { CardHoverReveal } from "@/components/ui/card-hover-reveal"
<CardHoverReveal />