User Menu
Auth & UserUser profile dropdown menu.
Preview
Usage
example.jsx
import { UserMenu } from "@/components/ui/user-menu";
export default function Example() {
return <UserMenu />;
}Source Code
Copy this file into components/ui/user-menu.jsx in your project.
user-menu.jsx
"use client";
import { forwardRef, useState, useRef, useEffect } from "react";
import { cn } from "@/lib/utils";
const UserMenu = forwardRef(({ className, user = {}, menuItems = [], ...props }, ref) => {
const [open, setOpen] = useState(false);
const menuRef = useRef(null);
useEffect(() => {
const handler = (e) => { if (menuRef.current && !menuRef.current.contains(e.target)) setOpen(false); };
document.addEventListener("mousedown", handler);
return () => document.removeEventListener("mousedown", handler);
}, []);
return (
<div ref={(el) => { menuRef.current = el; if (typeof ref === "function") ref(el); else if (ref) ref.current = el; }} className={cn("relative", className)} {...props}>
<button onClick={() => setOpen(!open)} className="flex items-center gap-2 rounded-full p-1 hover:bg-accent">
<div className="flex h-8 w-8 items-center justify-center rounded-full bg-primary text-sm font-medium text-primary-foreground">
{user.avatar ? <img src={user.avatar} alt="" className="h-full w-full rounded-full object-cover" /> : (user.name?.[0] || "U")}
</div>
<span className="hidden text-sm font-medium sm:block">{user.name}</span>
</button>
{open && (
<div className="absolute right-0 mt-2 w-56 rounded-md border bg-popover p-1 shadow-lg">
<div className="border-b px-3 py-2">
<div className="text-sm font-medium">{user.name}</div>
<div className="text-xs text-muted-foreground">{user.email}</div>
</div>
<div className="py-1">
{menuItems.map((item, i) => (
item.separator ? <div key={i} className="my-1 h-px bg-border" /> :
<button key={i} onClick={() => { item.onClick?.(); setOpen(false); }}
className="flex w-full items-center gap-2 rounded-sm px-3 py-1.5 text-sm hover:bg-accent"
>
{item.icon && <span>{item.icon}</span>}{item.label}
</button>
))}
</div>
</div>
)}
</div>
);
});
UserMenu.displayName = "UserMenu";
export { UserMenu };
Quick Install
Make sure you have the cn() utility set up. It requires clsx and tailwind-merge.
npm install clsx tailwind-merge