Pro Card
A premium profile card component with 3D hover effects, interactive animations, and multiple layout variants
Overview
The ProCard is a premium profile card component with 3D hover effects, interactive animations, and multiple layout variants. Perfect for showcasing user profiles, team members, or personal information with a modern, engaging interface.
Features
- 3D Hover Effects - Smooth tilt animation with perspective
- Interactive Animations - Shimmer effect on click and mouse-following glare
- Multiple Variants - Default, compact, and elegant layouts
- Light/Dark Mode - Fully adaptive styling for both themes
- Avatar Support - Next.js Image optimization for profile pictures
- Tech Stack Display - Badges for technologies and cloud services
- Contact Information - Email, location, and date with icons
- Custom Content - Support for custom children layouts
Installation
pro-card.tsx
'use client'
import { useRef, useState, MouseEvent } from 'react'
import { cn } from '@/lib/utils'
import Image from 'next/image'
import { MapPin, Mail, Code, Cloud } from 'lucide-react'
import { Calendar } from 'lucide-react'
interface ProCardProps {
avatar?: string
email?: string
location?: string
tech?: string[]
cloud?: string[]
name?: string
title?: string
date?: string
variant?: 'default' | 'compact' | 'elegant'
children?: React.ReactNode
className?: string
}
export const ProCard = ({
avatar,
email,
location,
tech = [],
cloud = [],
name,
title,
date,
variant = 'default',
children,
className,
}: ProCardProps) => {
const cardRef = useRef<HTMLDivElement>(null)
const [transform, setTransform] = useState('')
const [isGlaring, setIsGlaring] = useState(false)
const [glarePosition, setGlarePosition] = useState({ x: 0, y: 0 })
const handleMouseMove = (e: MouseEvent<HTMLDivElement>) => {
if (!cardRef.current) return
const card = cardRef.current
const rect = card.getBoundingClientRect()
const x = e.clientX - rect.left
const y = e.clientY - rect.top
const centerX = rect.width / 2
const centerY = rect.height / 2
const rotateX = ((y - centerY) / centerY) * -10
const rotateY = ((x - centerX) / centerX) * 10
setTransform(
`perspective(1000px) rotateX(${rotateX}deg) rotateY(${rotateY}deg) scale3d(1.02, 1.02, 1.02)`
)
setGlarePosition({ x, y })
}
const handleMouseLeave = () => {
setTransform('perspective(1000px) rotateX(0deg) rotateY(0deg) scale3d(1, 1, 1)')
}
const handleClick = () => {
setIsGlaring(true)
setTimeout(() => setIsGlaring(false), 800)
}
return (
<div className="perspective-1000">
<div
ref={cardRef}
onMouseMove={handleMouseMove}
onMouseLeave={handleMouseLeave}
onClick={handleClick}
className={cn(
'group relative cursor-pointer overflow-hidden rounded-none bg-zinc shadow-zinc-950/5 transition-all duration-300 ease-out',
'border border-zinc-200 dark:border-zinc-800',
'hover:shadow-2xl',
className
)}
style={{
transform,
transition: 'transform 0.1s ease-out, box-shadow 0.3s ease-out',
}}
>
{/* Background matching FeatureCard exactly */}
<div className="absolute inset-0 bg-zinc-50 dark:bg-transparent" />
{/* Corner Borders - Exact same as FeatureCard */}
<span className="border-primary absolute -left-px -top-px block size-2 border-l-2 border-t-2"></span>
<span className="border-primary absolute -right-px -top-px block size-2 border-r-2 border-t-2"></span>
<span className="border-primary absolute -bottom-px -left-px block size-2 border-b-2 border-l-2"></span>
<span className="border-primary absolute -bottom-px -right-px block size-2 border-b-2 border-r-2"></span>
{/* Shimmer overlay on click */}
{isGlaring && <div className="dark:shimmer-effect pointer-events-none absolute inset-0" />}
{/* Glare effect that follows mouse */}
<div
className="pointer-events-none absolute inset-0 opacity-0 transition-opacity duration-300 hover:opacity-100"
style={{
background: `radial-gradient(circle 200px at ${glarePosition.x}px ${glarePosition.y}px, hsl(var(--glare) / 0.15), transparent)`,
}}
/>
{/* Moving glare on click */}
{isGlaring && (
<div className="glare-effect pointer-events-none absolute inset-0">
<div className="absolute top-0 left-0 h-full w-full -skew-x-12 bg-gradient-to-r from-transparent via-white/30 to-transparent" />
</div>
)}
{/* Content */}
<div className="relative z-10 p-6">
{children ? (
children
) : variant === 'elegant' ? (
<div className="flex flex-col items-center gap-8 md:flex-row">
{/* Avatar */}
<div className="shrink-0">
{avatar ? (
<div className="relative h-32 w-32 overflow-hidden rounded-full shadow-xl ring-2 ring-white/30 md:h-40 md:w-40">
<Image src={avatar} alt={name || 'Profile'} fill className="object-cover" />
</div>
) : (
<div className="from-primary/20 to-secondary/20 h-32 w-32 rounded-full border-2 border-white/30 bg-gradient-to-br shadow-xl backdrop-blur-sm md:h-40 md:w-40" />
)}
</div>
{/* Content */}
<div className="flex-1 space-y-4 text-center md:text-left">
<div>
{name && (
<h1 className="from-primary via-secondary to-accent mb-2 bg-gradient-to-r bg-clip-text text-4xl font-bold text-transparent md:text-5xl">
{name}
</h1>
)}
{title && <p className="text-muted-foreground text-lg font-medium">{title}</p>}
</div>
<div className="text-muted-foreground space-y-2 text-sm">
{email && (
<div className="flex items-center justify-center gap-2 md:justify-start">
<Mail className="h-4 w-4" />
<span>{email}</span>
</div>
)}
{location && (
<div className="flex items-center justify-center gap-2 md:justify-start">
<MapPin className="h-4 w-4" />
<span>{location}</span>
</div>
)}
{date && (
<div className="flex items-center justify-center gap-2 md:justify-start">
<Calendar className="h-4 w-4" />
<span>{date}</span>
</div>
)}
</div>
<div className="border-t border-white/20 pt-4">
{tech && tech.length > 0 && (
<p className="text-foreground/80 mb-1 text-sm font-semibold">
Tech: {tech.join(' ').toUpperCase()}
</p>
)}
{cloud && cloud.length > 0 && (
<p className="text-foreground/80 text-sm font-semibold">
CLOUD: {cloud.join(', ').toUpperCase()}
</p>
)}
</div>
</div>
</div>
) : variant === 'compact' ? (
<div className="flex items-center gap-4">
{avatar && (
<div className="ring-primary/20 dark:ring-primary/30 relative h-16 w-16 flex-shrink-0 overflow-hidden rounded-xl ring-2">
<Image src={avatar} alt={name || 'Profile'} fill className="object-cover" />
</div>
)}
<div className="min-w-0 flex-1">
{name && (
<h3 className="text-foreground mb-1 truncate text-xl font-bold">{name}</h3>
)}
{title && <p className="text-muted-foreground mb-2 text-sm">{title}</p>}
<div className="text-muted-foreground flex flex-wrap gap-4 text-xs">
{email && (
<div className="flex items-center gap-1">
<Mail className="h-3 w-3" />
<span className="truncate">{email}</span>
</div>
)}
{location && (
<div className="flex items-center gap-1">
<MapPin className="h-3 w-3" />
<span className="truncate">{location}</span>
</div>
)}
</div>
{(tech.length > 0 || cloud.length > 0) && (
<div className="mt-2 flex flex-wrap gap-1">
{tech.slice(0, 3).map((item, index) => (
<span
key={index}
className="bg-primary/10 dark:bg-primary/20 text-primary rounded px-2 py-0.5 text-xs font-medium"
>
{item}
</span>
))}
{cloud.slice(0, 2).map((item, index) => (
<span
key={index}
className="bg-accent dark:bg-accent/50 text-accent-foreground rounded px-2 py-0.5 text-xs font-medium"
>
{item}
</span>
))}
</div>
)}
</div>
</div>
) : (
<div className="flex flex-col gap-6">
{/* Avatar and Info Section */}
<div className="flex items-start gap-4">
{avatar && (
<div className="ring-primary/20 dark:ring-primary/30 relative h-20 w-20 flex-shrink-0 overflow-hidden rounded-2xl ring-2">
<Image src={avatar} alt={name || 'Profile'} fill className="object-cover" />
</div>
)}
<div className="min-w-0 flex-1">
{name && (
<h3 className="text-foreground mb-1 truncate text-2xl font-bold">{name}</h3>
)}
{title && <p className="text-muted-foreground mb-3 text-sm">{title}</p>}
<div className="flex flex-col gap-2">
{email && (
<div className="text-muted-foreground flex items-center gap-2 text-sm">
<Mail className="h-4 w-4 flex-shrink-0" />
<span className="truncate">{email}</span>
</div>
)}
{location && (
<div className="text-muted-foreground flex items-center gap-2 text-sm">
<MapPin className="h-4 w-4 flex-shrink-0" />
<span className="truncate">{location}</span>
</div>
)}
</div>
</div>
</div>
{/* Tech Stack */}
{tech && tech.length > 0 && (
<div className="space-y-2">
<div className="text-foreground flex items-center gap-2 text-sm font-semibold">
<Code className="h-4 w-4" />
<span>Tech Stack</span>
</div>
<div className="flex flex-wrap gap-2">
{tech.map((item, index) => (
<span
key={index}
className="bg-primary/10 dark:bg-primary/20 text-primary border-primary/20 rounded-full border px-3 py-1 text-xs font-medium"
>
{item}
</span>
))}
</div>
</div>
)}
{/* Cloud Services */}
{cloud && cloud.length > 0 && (
<div className="space-y-2">
<div className="text-foreground flex items-center gap-2 text-sm font-semibold">
<Cloud className="h-4 w-4" />
<span>Cloud & Tools</span>
</div>
<div className="flex flex-wrap gap-2">
{cloud.map((item, index) => (
<span
key={index}
className="bg-accent dark:bg-accent/50 text-accent-foreground border-border rounded-full border px-3 py-1 text-xs font-medium"
>
{item}
</span>
))}
</div>
</div>
)}
</div>
)}
</div>
</div>
</div>
)
}Variants
Default Variant
The standard layout with medium-sized avatar and detailed sections.
John Doe
Full Stack Developer
Elegant Variant
A modern layout with large avatar, gradient text, and clean design. Perfect for hero sections or featured profiles.

Arnab Das
Design Engineer
Tech: NEXT.JS TYPESCRIPT
CLOUD: AWS, GCP
Compact Variant
A space-efficient horizontal layout perfect for grids, sidebars, or list views.
Jane Smith
UI/UX Designer
Custom Content
You can also pass custom content using the children prop to create any layout you want.
Custom Content
You can pass any children you want to create custom layouts!
All Variants Showcase
Here's a complete showcase of all ProCard variants:
Elegant Variant

Arnab Das
Design Engineer
Tech: NEXT.JS TYPESCRIPT
CLOUD: AWS, GCP
Default Variant
John Doe
Full Stack Developer
Compact Variant
Jane Smith
UI/UX Designer
Installation
Manual Installation
Copy the ProCard component to your project:
# Copy the component file
cp components/aesthe-ui/cards/pro-card.tsx your-project/components/Dependencies
The ProCard component requires these dependencies:
npm install next lucide-react clsx tailwind-mergeProps
ProCardProps
| Prop | Type | Default | Description |
|---|---|---|---|
avatar | string | - | Avatar image URL |
name | string | - | Person's name |
title | string | - | Job title or role |
email | string | - | Email address |
location | string | - | Location information |
date | string | - | Date information (shown in elegant variant) |
tech | string[] | [] | Array of technology names |
cloud | string[] | [] | Array of cloud service names |
variant | "default" | "compact" | "elegant" | "default" | Layout variant |
children | React.ReactNode | - | Custom content (overrides default layout) |
className | string | - | Additional CSS classes |
Usage Examples
Basic Profile Card
import { ProCard } from '@/components/aesthe-ui/cards/pro-card'
export default function ProfilePage() {
return (
<ProCard
avatar="https://example.com/avatar.jpg"
name="John Doe"
title="Full Stack Developer"
email="john.doe@example.com"
location="San Francisco, CA"
tech={["React", "Next.js", "TypeScript"]}
cloud={["AWS", "Vercel", "Docker"]}
/>
)
}Team Member Grid
import { ProCard } from '@/components/aesthe-ui/cards/pro-card'
const teamMembers = [
{
name: "Alice Johnson",
title: "Frontend Developer",
email: "alice@company.com",
location: "Remote",
tech: ["React", "Vue", "Svelte"],
cloud: ["Vercel", "Netlify"]
},
{
name: "Bob Smith",
title: "Backend Developer",
email: "bob@company.com",
location: "New York",
tech: ["Node.js", "Python", "Go"],
cloud: ["AWS", "Docker", "Kubernetes"]
}
]
export default function TeamPage() {
return (
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
{teamMembers.map((member, index) => (
<ProCard
key={index}
variant="compact"
name={member.name}
title={member.title}
email={member.email}
location={member.location}
tech={member.tech}
cloud={member.cloud}
/>
))}
</div>
)
}Hero Section
import { ProCard } from '@/components/aesthe-ui/cards/pro-card'
export default function HeroSection() {
return (
<section className="min-h-screen flex items-center justify-center">
<ProCard
variant="elegant"
avatar="https://example.com/founder.jpg"
name="Sarah Wilson"
title="Founder & CEO"
email="sarah@company.com"
location="San Francisco, CA"
date="Founded 2020"
tech={["Next.js", "TypeScript", "Tailwind CSS"]}
cloud={["AWS", "Vercel", "Stripe"]}
className="max-w-2xl"
/>
</section>
)
}Customization
Styling
You can customize the ProCard appearance using the className prop:
<ProCard
className="max-w-lg mx-auto shadow-2xl"
// ... other props
/>CSS Variables
The component uses CSS variables for theming. You can override these in your global CSS:
:root {
--glare-light: 255 255 255;
--glare-opacity: 0.4;
}
.dark {
--glare-light: 200 200 255;
--glare-opacity: 0.25;
}Custom Animations
The ProCard includes several CSS animations that you can customize:
@keyframes shimmer-sweep {
0% {
transform: translateX(-100%) translateY(-100%) rotate(30deg);
}
100% {
transform: translateX(100%) translateY(100%) rotate(30deg);
}
}
.shimmer-effect {
animation: shimmer-sweep 0.8s ease-out;
}Accessibility
The ProCard component includes several accessibility features:
- Keyboard Navigation - All interactive elements are keyboard accessible
- Screen Reader Support - Proper ARIA labels and semantic HTML
- Focus Management - Clear focus indicators for keyboard users
- Reduced Motion - Respects user's motion preferences
Browser Support
The ProCard component works in all modern browsers that support:
- CSS Grid and Flexbox
- CSS Custom Properties (CSS Variables)
- CSS Transforms and Transitions
- ES6+ JavaScript features
Performance
The ProCard is optimized for performance:
- Next.js Image Optimization - Automatic image optimization for avatars
- Efficient Animations - Uses CSS transforms for smooth 60fps animations
- Minimal Re-renders - Optimized React state management
- Lazy Loading - Images load only when needed