logo
CtrlK
ComponentsTemplates

Components

Accordion
Alert
Avatar
Badge
Banner
Bottom Navigation
Breadcrumb
Button
Call to Action
Card
Date Picker
Divider
Dropdown
Featues
File Upload
Footer
Header
Hero
Loader
Pagination
Popover
Sidebar
Skeleton
Social Share
Tabs
Testimonial
Tooltip

Pages

Error Pages
Blog List
  1. Docs
  2. Components
  3. Dropdown

Dropdown

Dropdowns are toggleable, contextual overlays for displaying lists of links and actions in a dropdown menu format.

Simple Dropdown

import React, { useState } from "react";
import { ChevronDown } from "lucide-react";

const Dropdown = () => {
  const [isOpen, setIsOpen] = useState(false);
  const [selected, setSelected] = useState("Choose an option");

  const options = ["Option 1", "Option 2", "Option 3"];

  return (
    <div className="h-screen flex justify-center items-center bg-gray-50/50 dark:bg-gray-900/50">
      <div className="relative inline-block text-left">
        <button
          type="button"
          className="inline-flex justify-center items-center w-full rounded-xl border border-gray-200 dark:border-gray-700 px-4 py-2.5 bg-white/80 dark:bg-gray-800/80 text-sm font-medium text-gray-700 dark:text-gray-200 hover:bg-white dark:hover:bg-gray-800 transition-all shadow-sm hover:shadow-md"
          onClick={() => setIsOpen(!isOpen)}
        >
          {selected}
          <ChevronDown
            className={`ml-2 h-4 w-4 transition-transform duration-200 ${
              isOpen ? "rotate-180" : ""
            }`}
          />
        </button>

        {isOpen && (
          <div className="absolute right-0 mt-2 w-56 rounded-xl shadow-lg bg-white/90 dark:bg-gray-800/90 border border-gray-100 dark:border-gray-700 transform transition-all">
            <div className="py-1 rounded-xl overflow-hidden">
              {options.map((option) => (
                <button
                  key={option}
                  className="w-full text-left px-4 py-2.5 text-sm text-gray-700 dark:text-gray-200 hover:bg-gray-50 dark:hover:bg-gray-700/50 transition-colors"
                  onClick={() => {
                    setSelected(option);
                    setIsOpen(false);
                  }}
                >
                  {option}
                </button>
              ))}
            </div>
          </div>
        )}
      </div>
    </div>
  );
};

export default Dropdown;

Dropdown with Icons

import React, { useState } from "react";
import { ChevronDown, LogOut, Mail, Settings } from "lucide-react";

const Dropdown = () => {
  const [isOpen, setIsOpen] = useState(false);

  const options = [
    { label: "Messages", icon: Mail },
    { label: "Settings", icon: Settings },
    {
      label: "Logout",
      icon: LogOut,
      className: "text-red-500 dark:text-red-400",
    },
  ];

  return (
    <div className="h-screen flex justify-center items-center bg-gray-50/50 dark:bg-gray-900/50">
      <div className="relative inline-block text-left">
        <button
          type="button"
          className="inline-flex justify-center items-center w-full rounded-xl border border-gray-200 dark:border-gray-700 px-4 py-2.5 bg-white/80 dark:bg-gray-800/80 text-sm font-medium text-gray-700 dark:text-gray-200 hover:bg-white dark:hover:bg-gray-800 transition-all shadow-sm hover:shadow-md"
          onClick={() => setIsOpen(!isOpen)}
        >
          Options
          <ChevronDown
            className={`ml-2 h-4 w-4 transition-transform duration-200 ${
              isOpen ? "rotate-180" : ""
            }`}
          />
        </button>

        {isOpen && (
          <div className="absolute right-0 mt-2 w-56 rounded-xl shadow-lg bg-white/90 dark:bg-gray-800/90 border border-gray-100 dark:border-gray-700">
            <div className="py-1 rounded-xl overflow-hidden">
              {options.map((option) => (
                <button
                  key={option.label}
                  className={`w-full text-left flex items-center px-4 py-2.5 text-sm text-gray-700 dark:text-gray-200 hover:bg-gray-50 dark:hover:bg-gray-700/50 transition-colors ${
                    option.className || ""
                  }`}
                  onClick={() => setIsOpen(false)}
                >
                  <option.icon className="mr-3 h-4 w-4" aria-hidden="true" />
                  {option.label}
                </button>
              ))}
            </div>
          </div>
        )}
      </div>
    </div>
  );
};

export default Dropdown;

Dropdown with Search

import React, { useEffect, useRef, useState } from "react";
import { ChevronDown, Search } from "lucide-react";

const Dropdown = () => {
  const [isOpen, setIsOpen] = useState(false);
  const [searchTerm, setSearchTerm] = useState("");
  const [selected, setSelected] = useState<string | null>(null);
  const dropdownRef = useRef<HTMLDivElement>(null);

  const options = [
    "Apple",
    "Banana",
    "Cherry",
    "Date",
    "Elderberry",
    "Fig",
    "Grape",
    "Honeydew",
    "Kiwi",
    "Lemon",
  ];

  const filteredOptions = options.filter((option) =>
    option.toLowerCase().includes(searchTerm.toLowerCase())
  );

  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);
  }, []);

  return (
    <div className="h-screen flex justify-center items-center bg-gray-50/50 dark:bg-gray-900/50">
      <div className="relative inline-block text-left" ref={dropdownRef}>
        <button
          type="button"
          className="inline-flex justify-between items-center w-64 rounded-xl border border-gray-200 dark:border-gray-700 px-4 py-2.5 bg-white/80 dark:bg-gray-800/80 text-sm font-medium text-gray-700 dark:text-gray-200 hover:bg-white dark:hover:bg-gray-800 transition-all shadow-sm hover:shadow-md"
          onClick={() => setIsOpen(!isOpen)}
        >
          {selected || "Select a fruit"}
          <ChevronDown
            className={`ml-2 h-4 w-4 transition-transform duration-200 ${
              isOpen ? "rotate-180" : ""
            }`}
          />
        </button>

        {isOpen && (
          <div className="absolute right-0 mt-2 w-64 rounded-xl shadow-lg bg-white/90 dark:bg-gray-800/90 border border-gray-100 dark:border-gray-700">
            <div className="p-2">
              <div className="relative">
                <Search className="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400 dark:text-gray-300 h-4 w-4" />
                <input
                  type="text"
                  className="w-full pl-9 pr-4 py-2 rounded-lg text-sm bg-gray-50 dark:bg-gray-700/50 border border-gray-200 dark:border-gray-600 text-gray-900 dark:text-gray-100 placeholder-gray-400 dark:placeholder-gray-500 focus:outline-none focus:ring-2 focus:ring-blue-500/20 transition-all"
                  placeholder="Search fruits..."
                  value={searchTerm}
                  onChange={(e) => setSearchTerm(e.target.value)}
                />
              </div>
            </div>
            <div className="max-h-60 overflow-y-auto scrollbar-thin scrollbar-thumb-gray-200 dark:scrollbar-thumb-gray-700 px-1">
              {filteredOptions.length > 0 ? (
                filteredOptions.map((option) => (
                  <button
                    key={option}
                    className="w-full text-left px-4 py-2.5 text-sm text-gray-700 dark:text-gray-200 hover:bg-gray-50 dark:hover:bg-gray-700/50 rounded-lg transition-colors"
                    onClick={() => {
                      setSelected(option);
                      setIsOpen(false);
                      setSearchTerm("");
                    }}
                  >
                    {option}
                  </button>
                ))
              ) : (
                <div className="px-4 py-2.5 text-sm text-gray-500 dark:text-gray-400">
                  No results found
                </div>
              )}
            </div>
          </div>
        )}
      </div>
    </div>
  );
};

export default Dropdown;

Divider

Featues

On this page

Simple DropdownDropdown with IconsDropdown with Search
logo

Empowering developers with intuitive and efficient UI components.

Created by Abhay Singh Rathore, a passionate Full-Stack Developer & UI/UX designer.

Quick Links

  • Home
  • Components
  • Templates

Connect

© 2025 Business Wish. All rights reserved.