// src/components/LoginTooltip/LoginTooltip.tsx
"use client";
import {
LogOut,
User,
ShoppingBag,
Heart,
MapPin,
CreditCard,
Package,
HelpCircle,
Settings,
ChevronRight,
} from "lucide-react";
import React, { useState } from "react";
import { motion, AnimatePresence } from "framer-motion";
const menuItems = [
{ icon: Package, label: "My Orders", href: "#" },
{ icon: Heart, label: "Wishlist", href: "#" },
{ icon: ShoppingBag, label: "Cart", href: "#" },
{ icon: MapPin, label: "Addresses", href: "#" },
{ icon: CreditCard, label: "Payments", href: "#" },
{ icon: Settings, label: "Account Settings", href: "#" },
{ icon: HelpCircle, label: "Help & Support", href: "#" },
];
function LoginTooltip() {
const [isOpen, setIsOpen] = useState(false);
return (
<div
className="relative inline-block"
onMouseEnter={() => setIsOpen(true)}
onMouseLeave={() => setIsOpen(false)}
>
{/* Trigger */}
<button className="relative border border-gray-300 rounded-full p-2.5 bg-white hover:bg-gray-50 hover:border-gray-400 transition-colors duration-200 cursor-pointer">
<User className="w-5 h-5 text-gray-700" />
<span className="absolute top-0 right-0 w-2.5 h-2.5 bg-green-500 border-2 border-white rounded-full" />
</button>
{/* Dropdown container — pt-2 creates the gap but keeps it hoverable */}
<AnimatePresence>
{isOpen && (
<motion.div
initial={{ opacity: 0, y: 4 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: 4 }}
transition={{ duration: 0.15, ease: "easeOut" }}
className="absolute top-full right-0 pt-2 z-50"
>
<div className="w-60 bg-white border border-gray-200 rounded-xl shadow-xl overflow-hidden">
{/* Header */}
<div className="px-4 py-3 border-b border-gray-100 bg-gray-50/50">
<p className="text-sm font-semibold text-gray-900">
Prince Vishwakarma
</p>
<p className="text-xs text-gray-500 mt-0.5">
prince@example.com
</p>
</div>
{/* Menu */}
<ul className="py-1">
{menuItems.map((item, index) => (
<motion.li
key={item.label}
initial={{ opacity: 0, x: -6 }}
animate={{ opacity: 1, x: 0 }}
transition={{ delay: index * 0.02, duration: 0.12 }}
>
<a
href={item.href}
className="flex items-center justify-between px-4 py-2 text-sm text-gray-700 hover:bg-gray-50 hover:text-gray-900 transition-colors duration-150 cursor-pointer"
>
<div className="flex items-center gap-3">
<item.icon className="w-4 h-4 text-gray-500" />
<span>{item.label}</span>
</div>
<ChevronRight className="w-3.5 h-3.5 text-gray-400" />
</a>
</motion.li>
))}
</ul>
{/* Logout */}
<div className="border-t border-gray-100 py-1.5 px-4">
<button className="flex items-center gap-3 w-full py-2 text-sm text-red-600 hover:text-red-700 hover:bg-red-50 rounded-lg transition-colors duration-150 cursor-pointer">
<LogOut className="w-4 h-4" />
<span>Sign Out</span>
</button>
</div>
</div>
</motion.div>
)}
</AnimatePresence>
</div>
);
}
export default LoginTooltip;Component details
Overview, install command, dependencies, and project links.
A hover-triggered user profile dropdown menu built with React, Tailwind CSS, and Framer Motion. Includes a user avatar button with a green online status indicator, animated dropdown panel with smooth fade and slide transition, staggered menu item animations, user name and email header, icon-based navigation links, and a sign out button - all in one clean reusable component. Perfect for dashboards, e-commerce sites, SaaS apps, and any project that needs a ready-to-use profile menu. Menu items are defined in a simple array so adding or removing links takes one line. Works with Next.js App Router as a client component and with React Vite with zero changes.
Install
npm install framer-motion lucide-reactDependencies
Discussion
Feedback, implementation tips, and usage notes.
Comments
Sign in to join the conversation
Similar Components
More from the same category


