Dropdown Menu
Overlay & FeedbackDropdown menu triggered by a button click.
Preview
Usage
example.jsx
import { DropdownMenu, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuLabel } from "@/components/ui/dropdown-menu";
export default function Example() {
return <DropdownMenu />;
}Source Code
Copy this file into components/ui/dropdown-menu.jsx in your project.
dropdown-menu.jsx
"use client";
import { forwardRef, useState, useRef, useEffect } from "react";
import { cn } from "@/lib/utils";
const DropdownMenu = forwardRef(({ className, trigger, children, align = "start", ...props }, ref) => {
const [open, setOpen] = useState(false);
const dropdownRef = useRef(null);
useEffect(() => {
const handler = (e) => { if (dropdownRef.current && !dropdownRef.current.contains(e.target)) setOpen(false); };
document.addEventListener("mousedown", handler);
return () => document.removeEventListener("mousedown", handler);
}, []);
return (
<div ref={(el) => { dropdownRef.current = el; if (typeof ref === "function") ref(el); else if (ref) ref.current = el; }} className={cn("relative inline-block", className)} {...props}>
<div onClick={() => setOpen(!open)}>{trigger}</div>
{open && (
<div className={cn("absolute z-50 mt-1 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md animate-in fade-in-0 zoom-in-95",
align === "end" ? "right-0" : "left-0"
)}>
{children}
</div>
)}
</div>
);
});
DropdownMenu.displayName = "DropdownMenu";
const DropdownMenuItem = forwardRef(({ className, ...props }, ref) => (
<button ref={ref} className={cn("relative flex w-full cursor-pointer select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors hover:bg-accent hover:text-accent-foreground", className)} {...props} />
));
DropdownMenuItem.displayName = "DropdownMenuItem";
const DropdownMenuSeparator = forwardRef(({ className, ...props }, ref) => (
<div ref={ref} className={cn("-mx-1 my-1 h-px bg-border", className)} {...props} />
));
DropdownMenuSeparator.displayName = "DropdownMenuSeparator";
const DropdownMenuLabel = forwardRef(({ className, ...props }, ref) => (
<div ref={ref} className={cn("px-2 py-1.5 text-xs font-semibold", className)} {...props} />
));
DropdownMenuLabel.displayName = "DropdownMenuLabel";
export { DropdownMenu, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuLabel };
Quick Install
Make sure you have the cn() utility set up. It requires clsx and tailwind-merge.
npm install clsx tailwind-merge