Socket
Book a DemoInstallSign in
Socket

@asafarim/dd-menu

Package Overview
Dependencies
Maintainers
1
Versions
33
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@asafarim/dd-menu

A minimal, elegant, and highly customizable dropdown menu React component. Perfect for navbar, sidebar, or any dropdown needs with beautiful theming and smooth animations.

latest
Source
npmnpm
Version
1.4.0
Version published
Maintainers
1
Created
Source

@asafarim/dd-menu

npm version TypeScript License: MIT

A powerful, customizable dropdown menu and searchable dropdown component library for React with TypeScript. Features recursive nesting, multiple themes, custom triggers, keyboard navigation, and accessibility support. See a live demo at alisafari-it.github.io for different use cases.

DD Menu Showcase

Components

DDMenu - Dropdown Menu

A flexible dropdown menu component with support for nested items, custom triggers, and multiple variants.

DDSearchable - Searchable Dropdown

A powerful searchable dropdown component with filtering, keyboard navigation, and customizable search behavior.

Features

  • 🔄 Recursive Nesting: Create unlimited nested dropdown menus
  • 🔍 Searchable Dropdown: Filter items with real-time search and keyboard navigation
  • 🎨 Multiple Variants: Choose from default, minimal, outlined, filled, navbar, and sidebar styles
  • 🌓 Theme Support: Built-in light, dark, and auto themes
  • 📱 Responsive: Works perfectly on all device sizes
  • Accessible: Full keyboard navigation and ARIA support
  • 🔧 Highly Customizable: Custom triggers, icons, styling, and search configuration
  • Performance: Debounced search, virtual scrolling support, and optimized rendering
  • 🧩 Zero Dependencies: Pure React and CSS implementation

Installation

# Using npm
npm install @asafarim/dd-menu

# Using yarn
yarn add @asafarim/dd-menu

# Using pnpm
pnpm add @asafarim/dd-menu

Quick Start

import DDMenu, { DDSearchable, MenuItem } from "@asafarim/dd-menu";

const App = () => {
  const menuItems: MenuItem[] = [
    { id: "home", label: "Home", link: "/", icon: "🏠" },
    {
      id: "products",
      label: "Products",
      icon: "📦",
      children: [
        { id: "electronics", label: "Electronics", link: "/products/electronics" },
        { id: "clothing", label: "Clothing", link: "/products/clothing" },
      ],
    },
    { id: "about", label: "About Us", link: "/about", icon: "ℹ️" },
  ];

  return (
    <div>
      {/* Dropdown Menu */}
      <DDMenu 
        items={menuItems} 
        theme="auto" 
        variant="default" 
        size="md" 
        placement="bottom-start"
        closeOnClick={true}
        onItemClick={(item) => console.log('Clicked:', item)}
      />

      {/* Searchable Dropdown */}
      <DDSearchable
        items={menuItems}
        placeholder="Search items..."
        onItemSelect={(item) => console.log('Selected:', item)}
        theme="auto"
        size="md"
      />
    </div>
  );
};

Theming

Both DDMenu and DDSearchable support theme="light" | "dark" | "auto".

  • Root theme class: the root element receives dd-menu--{theme} / dd-searchable--{theme}.
  • Auto mode: respects OS preference via prefers-color-scheme. If your app sets a theme attribute on a parent (e.g. <html data-theme="light">), it overrides auto so the app choice wins.
  • CSS variables: colors are driven by CSS custom properties like --dd-bg, --dd-text, --dd-border, etc.

If you have a global theme toggle, set data-theme="light" or data-theme="dark" on html or body so all menus follow your app’s theme while using theme="auto".

DDMenu Usage

Basic Dropdown Menu

<DDMenu
  items={menuItems}
  variant="default"
  onItemClick={(item) => console.log(item)}
/>

Custom Trigger

const customTrigger = (
  <button className="my-button">
    Action Menu
  </button>
);

<DDMenu
  items={menuItems}
  variant="minimal"
  trigger={customTrigger}
  onItemClick={(item) => console.log(item)}
/>

Navbar Profile Menu

const profileTrigger = (
  <div className="profile-trigger">
    <div className="avatar">JD</div>
    <span>John Doe</span>
  </div>
);

<DDMenu
  items={profileMenuItems}
  variant="navbar"
  trigger={profileTrigger}
  placement="bottom-end"
  onItemClick={handleProfileAction}
/>

Sidebar Navigation

const sidebarItems = [
  { id: "dashboard", label: "Dashboard", icon: "📊" },
  {
    id: "products",
    label: "Products",
    icon: "📦",
    children: [
      { id: "list", label: "Product List" },
      { id: "add", label: "Add Product" }
    ]
  }
];

<DDMenu
  items={sidebarItems}
  variant="sidebar"
  onItemClick={handleNavigation}
/>

DDSearchable Usage

Basic Searchable Dropdown

<DDSearchable
  items={menuItems}
  placeholder="Search items..."
  onItemSelect={(item) => console.log('Selected:', item)}
/>

Different Variants

<DDSearchable variant="default" items={items} />
<DDSearchable variant="minimal" items={items} />
<DDSearchable variant="outlined" items={items} />
<DDSearchable variant="filled" items={items} />

Advanced Search Configuration

<DDSearchable
  items={items}
  caseSensitive={true}
  minSearchLength={2}
  debounceMs={500}
  searchKeys={["label", "id"]}
  onSearchChange={(term) => console.log("Search:", term)}
/>

Allow Custom Values

<DDSearchable
  items={items}
  allowCustomValue={true}
  onCustomValue={(value) => {
    // Handle custom value
    console.log('Custom value:', value);
    // You could add it to your items list
  }}
  placeholder="Type anything..."
/>

Controlled Component

const [selectedItem, setSelectedItem] = useState(null);

<DDSearchable
  items={items}
  selectedItem={selectedItem}
  onItemSelect={setSelectedItem}
  clearable={true}
/>

Showcase Examples

Navigation Menu

Navbar Dropdown

<DDMenu
  items={navMenuItems}
  className="dd-menu--navbar"
  placement="bottom"
  closeOnClick={true}
  size="lg"
  theme="auto"
  trigger={
    <div className="dd-menu__trigger dd-menu__trigger--text">
      Navigation
    </div>
  }
/>

User Profile Menu

User Profile Dropdown

<DDMenu
  items={profileMenuItems}
  className="dd-menu--navbar"
  trigger={
    <div className="user-profile-trigger">
      <div className="avatar">JD</div>
      <span>John Doe</span>
    </div>
  }
  placement="bottom-end"
/>

Custom Button Trigger

<DDMenu 
  items={navMenuItems} 
  className="dd-menu--minimal"
  trigger={
    <button className="action-button">
      Action Menu
    </button>
  }
/>

API Reference

DDMenu Props

PropTypeDefaultDescription
itemsMenuItem[]RequiredArray of menu items
theme'light' | 'dark' | 'auto''auto'Theme for this menu
variant'default' | 'minimal' | 'navbar' | 'sidebar''default'Visual variant
size'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl''md'Font sizing preset
placement'bottom' | 'bottom-start' | 'bottom-end' | 'top' | 'top-start' | 'top-end' | 'right' | 'left''bottom-start'Dropdown placement
closeOnClickbooleantrueClose menu when an item is clicked
hoverDelaynumber150Delay (ms) for opening submenus on hover
triggerReactNodeDefault buttonCustom trigger element
onItemClick(item: MenuItem) => voidundefinedItem click callback
onHoverChange(isHovering: boolean) => voidundefinedHover state callback
onFontSizeChange(size: DDMenuSize) => voidundefinedEmits internal font size
classNamestring''Additional CSS class names
styleCSSProperties{}Inline styles

MenuItem Type

type MenuItem = {
  id: string;
  label: string;
  link?: string;
  icon?: string | ReactNode;
  onClick?: () => void;
  disabled?: boolean;
  children?: MenuItem[];
};

DDSearchable Props

PropTypeDefaultDescription
itemsMenuItem[]RequiredItems to search (supports nesting)
theme'light' | 'dark' | 'auto''auto'Component theme
variant'default' | 'minimal' | 'outlined' | 'filled''default'Visual variant
size'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl''md'Font sizing preset
placeholderstring'Search...'Input placeholder
onItemSelect(item: MenuItem) => voidundefinedFired when an item is selected
onSearchChange(term: string) => voidundefinedFired on input changes (debounced)
disabledbooleanfalseDisable the control
clearablebooleantrueShow a clear button
maxHeightnumber300Max dropdown height (px)
noResultsTextstring'No results found'Empty state label
searchKeys(keyof MenuItem)[]['label','id']Fields used for matching
caseSensitivebooleanfalseCase sensitivity for matching
minSearchLengthnumber0Minimum length to start filtering
debounceMsnumber300Debounce time for input changes
selectedItemMenuItem | nullnullControlled selected item
allowCustomValuebooleanfalseAllow arbitrary values
onCustomValue(value: string) => voidundefinedCalled when a custom value is chosen

Styling

The components expose CSS variables you can override at any scope:

:root {
  --dd-bg: #ffffff;
  --dd-text: #111827;
  --dd-border: #e5e7eb;
  --dd-bg-hover: #f9fafb;
  --dd-bg-active: #f3f4f6;
  --dd-accent: #3b82f6;
}

[data-theme="dark"] {
  --dd-bg: #18181b;
  --dd-text: #ffffff;
  --dd-border: #3f3f46;
  --dd-bg-hover: #27272a;
  --dd-bg-active: #3f3f46;
  --dd-accent: #60a5fa;
}

Accessibility

The dropdown menu is built with accessibility in mind:

  • Keyboard navigation (Tab, Enter, Escape, Arrow keys)
  • ARIA attributes for screen readers
  • Focus management for keyboard users
  • Proper contrast ratios for text

License

MIT © Ali Safari

Keywords

asafarim

FAQs

Package last updated on 10 Aug 2025

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts