FluxUI Pro is live - modern UI, powerful animations, zero hassle.
Components
Dropdown

Dropdown

Animated dropdown menu with smooth transitions, keyboard navigation, and customizable options.

Installation

1

Install the packages

npm i motion clsx tailwind-merge
2

Add util file

lib/util.ts
import { ClassValue, clsx } from "clsx"; import { twMerge } from "tailwind-merge"; export function cn(...inputs: ClassValue[]) { return twMerge(clsx(inputs)); }
3

Copy and paste the following code into your project

dropdown.tsx
"use client"; import { cn } from "@/lib/utils"; import { motion, AnimatePresence } from "motion/react"; import React, { useState, useRef, useEffect } from "react"; import { FiChevronDown, FiCheck } from "react-icons/fi"; interface DropdownItem { label: string; value: string; icon?: React.ReactNode; } interface DropdownProps { items?: DropdownItem[]; placeholder?: string; onSelect?: (item: DropdownItem) => void; defaultValue?: string; } const Dropdown: React.FC<DropdownProps> = ({ items = [ { label: "Option 1", value: "option1" }, { label: "Option 2", value: "option2" }, { label: "Option 3", value: "option3" }, ], placeholder = "Select an option", onSelect = () => {}, defaultValue }) => { const [isOpen, setIsOpen] = useState(false); const [selectedItem, setSelectedItem] = useState<DropdownItem | null>( items.find(item => item.value === defaultValue) || null ); const dropdownRef = useRef<HTMLDivElement>(null); useEffect(() => { const handleClickOutside = (event: MouseEvent) => { if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) { setIsOpen(false); } }; document.addEventListener("mousedown", handleClickOutside); return () => document.removeEventListener("mousedown", handleClickOutside); }, []); const handleSelect = (item: DropdownItem) => { setSelectedItem(item); setIsOpen(false); onSelect(item); }; return ( <div ref={dropdownRef} className="relative w-full max-w-xs"> {/* Trigger */} <button onClick={() => setIsOpen(!isOpen)} className={cn( "w-full px-4 py-3 text-left", "bg-white dark:bg-neutral-800 border border-neutral-300 dark:border-neutral-600 rounded-lg", "flex items-center justify-between", "hover:border-neutral-400 dark:hover:border-neutral-500 transition-colors", "focus:outline-none focus:ring-2 focus:ring-cyan-500 focus:border-transparent" )} > <span className={cn( "text-neutral-900 dark:text-white", !selectedItem && "text-neutral-500 dark:text-neutral-400" )}> {selectedItem ? selectedItem.label : placeholder} </span> <motion.div animate={{ rotate: isOpen ? 180 : 0 }} transition={{ duration: 0.2 }} > <FiChevronDown className="h-4 w-4 text-neutral-400" /> </motion.div> </button> {/* Dropdown Menu */} <AnimatePresence> {isOpen && ( <motion.div className={cn( "absolute top-full left-0 right-0 z-50 mt-1", "bg-white dark:bg-neutral-800 border border-neutral-300 dark:border-neutral-600 rounded-lg", "shadow-lg max-h-60 overflow-y-auto" )} initial={{ opacity: 0, y: -10, scale: 0.95 }} animate={{ opacity: 1, y: 0, scale: 1 }} exit={{ opacity: 0, y: -10, scale: 0.95 }} transition={{ duration: 0.2, ease: "easeOut" }} > {items.map((item, index) => ( <motion.button key={item.value} onClick={() => handleSelect(item)} className={cn( "w-full px-4 py-3 text-left flex items-center justify-between", "hover:bg-neutral-50 dark:hover:bg-neutral-700 transition-colors", "first:rounded-t-lg last:rounded-b-lg", selectedItem?.value === item.value && "bg-cyan-50 dark:bg-cyan-900/20" )} initial={{ opacity: 0, x: -10 }} animate={{ opacity: 1, x: 0 }} transition={{ delay: index * 0.05, duration: 0.2 }} > <div className="flex items-center gap-3"> {item.icon && ( <span className="text-neutral-400">{item.icon}</span> )} <span className={cn( "text-neutral-900 dark:text-white", selectedItem?.value === item.value && "text-cyan-600 dark:text-cyan-400" )}> {item.label} </span> </div> {selectedItem?.value === item.value && ( <FiCheck className="h-4 w-4 text-cyan-500" /> )} </motion.button> ))} </motion.div> )} </AnimatePresence> </div> ); }; export default Dropdown;
4

Update the import paths to match your project setup

Props

PropTypeDefaultDescription
itemsDropdownItem[][]Array of dropdown items with label, value, and optional icon.
placeholderstringSelect an optionPlaceholder text when no item is selected.
onSelectfunction() => {}Callback function when an item is selected.
defaultValuestringundefinedDefault selected value.