Hover Card

Hover card components are the digital tooltips of your application. They provide contextual information on hover with smooth animations, configurable delays, and professional styling.

Preview
Code

John Doe

Click to view profile

Installation

First, make sure you have the required dependencies:

npx @rajdevxd/aura-ui add hover-card
yarn @rajdevxd/aura-ui add hover-card
pnpm dlx @rajdevxd/aura-ui add hover-card
bunx --bun @rajdevxd/aura-ui add hover-card

Usage

Hover card components provide contextual information on hover:

import { HoverCard } from "@/components/ui/hover-card"

const UserProfile = () => {
  return (
    <HoverCard
      hoverContent={
        <div className="p-4">
          <div className="flex items-center space-x-3 mb-3">
            <img
              src="/avatar.jpg"
              alt="User"
              className="w-10 h-10 rounded-full"
            />
            <div>
              <h4 className="font-semibold">John Doe</h4>
              <p className="text-sm text-muted-foreground">Software Developer</p>
            </div>
          </div>
          <p className="text-sm text-muted-foreground mb-3">
            Passionate developer with 5+ years of experience in React and Node.js.
          </p>
          <div className="flex space-x-2">
            <button className="px-3 py-1 bg-blue-500 text-white rounded text-sm">
              View Profile
            </button>
            <button className="px-3 py-1 border rounded text-sm">
              Message
            </button>
          </div>
        </div>
      }
    >
      <div className="flex items-center space-x-2 p-2 rounded hover:bg-gray-100 cursor-pointer">
        <img src="/avatar.jpg" alt="User" className="w-8 h-8 rounded-full" />
        <span>John Doe</span>
      </div>
    </HoverCard>
  )
}

Props

PropTypeRequiredDescription
childrenReact.ReactNodeYesThe trigger element
hoverContentReact.ReactNodeNoContent to show on hover
hoverDelaynumberNoDelay before showing (default: 300ms)
classNamestringNoAdditional CSS classes

Features

  • Smooth Animations: Elegant fade-in and slide effects
  • Configurable Delays: Customizable hover timing
  • Rich Content: Support for complex content structures
  • Positioning: Automatic positioning with collision detection
  • Theme Aware: Adapts to your design system
  • Accessible: Keyboard navigation support
  • Performance: Optimized rendering and cleanup

Advanced Usage

With User Information

const UserHoverCard = ({ user }: { user: User }) => {
  return (
    <HoverCard
      hoverDelay={500}
      hoverContent={
        <div className="p-4 w-80">
          <div className="flex items-start space-x-3">
            <img
              src={user.avatar}
              alt={user.name}
              className="w-12 h-12 rounded-full"
            />
            <div className="flex-1">
              <h4 className="font-semibold text-lg">{user.name}</h4>
              <p className="text-sm text-muted-foreground mb-2">{user.role}</p>

              <div className="space-y-1 text-sm">
                <div className="flex items-center space-x-2">
                  <span>📧</span>
                  <span>{user.email}</span>
                </div>
                <div className="flex items-center space-x-2">
                  <span>📍</span>
                  <span>{user.location}</span>
                </div>
                <div className="flex items-center space-x-2">
                  <span>🕒</span>
                  <span>Last active: {user.lastActive}</span>
                </div>
              </div>

              <div className="flex space-x-2 mt-4">
                <button className="flex-1 px-3 py-2 bg-blue-500 text-white rounded text-sm font-medium">
                  View Profile
                </button>
                <button className="px-3 py-2 border rounded text-sm">
                  Message
                </button>
              </div>
            </div>
          </div>
        </div>
      }
    >
      <div className="flex items-center space-x-2 p-2 rounded hover:bg-gray-100 cursor-pointer">
        <img src={user.avatar} alt={user.name} className="w-8 h-8 rounded-full" />
        <span className="font-medium">{user.name}</span>
        <span className="text-sm text-muted-foreground">@{user.username}</span>
      </div>
    </HoverCard>
  )
}

With Product Information

const ProductHoverCard = ({ product }: { product: Product }) => {
  return (
    <HoverCard
      hoverContent={
        <div className="p-4 w-72">
          <img
            src={product.image}
            alt={product.name}
            className="w-full h-32 object-cover rounded-lg mb-3"
          />

          <div className="space-y-2">
            <h4 className="font-semibold text-lg">{product.name}</h4>
            <p className="text-sm text-muted-foreground">{product.description}</p>

            <div className="flex items-center justify-between">
              <span className="text-lg font-bold text-green-600">
                ${product.price}
              </span>
              <div className="flex items-center space-x-1">
                <span className="text-yellow-400">⭐</span>
                <span className="text-sm">{product.rating}</span>
                <span className="text-sm text-muted-foreground">
                  ({product.reviews} reviews)
                </span>
              </div>
            </div>

            <div className="flex space-x-2 mt-3">
              <button className="flex-1 px-3 py-2 bg-blue-500 text-white rounded text-sm font-medium">
                Add to Cart
              </button>
              <button className="px-3 py-2 border rounded text-sm">
                Quick View
              </button>
            </div>
          </div>
        </div>
      }
    >
      <div className="border rounded-lg p-3 hover:shadow-md transition-shadow cursor-pointer">
        <img
          src={product.image}
          alt={product.name}
          className="w-full h-24 object-cover rounded mb-2"
        />
        <h3 className="font-medium text-sm">{product.name}</h3>
        <p className="text-green-600 font-semibold">${product.price}</p>
      </div>
    </HoverCard>
  )
}

With Status Information

const StatusHoverCard = ({ status }: { status: Status }) => {
  const getStatusColor = (status: string) => {
    switch (status) {
      case 'online': return 'bg-green-500'
      case 'away': return 'bg-yellow-500'
      case 'busy': return 'bg-red-500'
      default: return 'bg-gray-500'
    }
  }

  return (
    <HoverCard
      hoverContent={
        <div className="p-3">
          <div className="flex items-center space-x-2">
            <div className={`w-3 h-3 rounded-full ${getStatusColor(status.type)}`} />
            <span className="font-medium capitalize">{status.type}</span>
          </div>
          <p className="text-sm text-muted-foreground mt-1">
            {status.message}
          </p>
          <p className="text-xs text-muted-foreground mt-1">
            Last updated: {status.lastUpdated}
          </p>
        </div>
      }
    >
      <div className="flex items-center space-x-2">
        <div className={`w-2 h-2 rounded-full ${getStatusColor(status.type)}`} />
        <span className="text-sm capitalize">{status.type}</span>
      </div>
    </HoverCard>
  )
}

Common Patterns

User Avatar with Details

<HoverCard
  hoverContent={
    <div className="p-4">
      <div className="flex items-center space-x-3">
        <img src="/avatar.jpg" alt="User" className="w-10 h-10 rounded-full" />
        <div>
          <h4 className="font-semibold">John Doe</h4>
          <p className="text-sm text-muted-foreground">Software Developer</p>
        </div>
      </div>
      <p className="text-sm mt-2">Bio and additional information...</p>
    </div>
  }
>
  <img src="/avatar.jpg" alt="User" className="w-8 h-8 rounded-full cursor-pointer" />
</HoverCard>
<HoverCard
  hoverContent={
    <div className="p-4 w-80">
      <img src="/preview.jpg" alt="Preview" className="w-full h-32 object-cover rounded mb-2" />
      <h4 className="font-semibold">Article Title</h4>
      <p className="text-sm text-muted-foreground">Brief description of the article...</p>
    </div>
  }
>
  <a href="/article" className="text-blue-500 hover:underline">
    Read the full article
  </a>
</HoverCard>

Button with Tooltip

<HoverCard
  hoverDelay={200}
  hoverContent={
    <div className="p-2">
      <p className="text-sm">Click to perform this action</p>
    </div>
  }
>
  <button className="px-4 py-2 bg-blue-500 text-white rounded">
    Action Button
  </button>
</HoverCard>

Customization

Custom Styling

<HoverCard
  className="custom-hover-card"
  hoverContent={
    <div className="p-4 bg-gradient-to-r from-blue-500 to-purple-600 text-white rounded-lg">
      <h4 className="font-semibold">Custom Styled Card</h4>
      <p className="text-sm opacity-90">Beautiful gradient background</p>
    </div>
  }
>
  <div className="p-2 border rounded hover:border-blue-500 transition-colors cursor-pointer">
    Hover for custom styling
  </div>
</HoverCard>

Animation Customization

// You can customize animations by modifying the component
// or using CSS classes for different effects

<HoverCard
  hoverContent={
    <div className="p-4 animate-in slide-in-from-top-2 fade-in-50 duration-300">
      <p>Custom animation effects</p>
    </div>
  }
>
  <div>Hover me</div>
</HoverCard>

Accessibility

Keyboard Navigation

// Hover cards work well with keyboard navigation
// Focus management is handled automatically

<HoverCard
  hoverContent={<div>Accessible content</div>}
>
  <button>Focusable trigger</button>
</HoverCard>

Screen Reader Support

// Content is properly announced to screen readers
<HoverCard
  hoverContent={
    <div role="tooltip" aria-label="User information">
      <p>User details...</p>
    </div>
  }
>
  <img src="/avatar.jpg" alt="User avatar" />
</HoverCard>

Performance Considerations

Debouncing

const OptimizedHoverCard = () => {
  const [isVisible, setIsVisible] = useState(false)
  const timeoutRef = useRef<NodeJS.Timeout>()

  const handleMouseEnter = () => {
    if (timeoutRef.current) clearTimeout(timeoutRef.current)
    timeoutRef.current = setTimeout(() => setIsVisible(true), 300)
  }

  const handleMouseLeave = () => {
    if (timeoutRef.current) clearTimeout(timeoutRef.current)
    timeoutRef.current = setTimeout(() => setIsVisible(false), 150)
  }

  // Cleanup on unmount
  useEffect(() => {
    return () => {
      if (timeoutRef.current) clearTimeout(timeoutRef.current)
    }
  }, [])

  return (
    <HoverCard
      hoverContent={isVisible ? <Content /> : null}
      hoverDelay={0} // Handle delay manually for optimization
    >
      <Trigger onMouseEnter={handleMouseEnter} onMouseLeave={handleMouseLeave} />
    </HoverCard>
  )
}

Contributing

Hover card components add depth to user interactions! Help us improve their positioning algorithms, add more animation options, and enhance their accessibility features.

Hover Card - because information deserves beautiful presentation! 💳✨