Home/Components/Buttons/Profile Dropdown Menu with Animation - React Tailwind CSS
Code · Live Preview
Componenttsx
// 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;
DesktopSandpack

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

terminal
npm
npm install framer-motion lucide-react

Dependencies

Famer MotionLucid React
Added Aug 24, 2026

Discussion

Feedback, implementation tips, and usage notes.

0 threads

Comments

Sign in to join the conversation