Files
sigpro-ui/docs/components/dropdown.md
2026-04-02 19:31:39 +02:00

10 KiB
Raw Blame History

Dropdown

Dropdown component for creating menus, selectors, and action panels that appear when triggered. Supports both array-based items and custom content.

Tag

Dropdown

Props

Prop Type Default Description
label string | VNode | Signal - Button label or content
icon string | VNode | Signal - Icon displayed next to label
items Array<MenuItem> | Signal<Array> - Array of menu items (alternative to children)
class string '' Additional CSS classes (DaisyUI + Tailwind)
children VNode | function - Custom dropdown content (alternative to items)

MenuItem Structure (when using items)

Property Type Description
label string | VNode Menu item text
icon string | VNode Optional icon for the menu item
onclick function Click handler
class string Additional CSS classes for the menu item

Styling

Dropdown supports all daisyUI Dropdown classes:

Category Keywords Description
Position dropdown-end Align dropdown to the right
Direction dropdown-top, dropdown-bottom, dropdown-left, dropdown-right Dropdown open direction
Hover dropdown-hover Open on hover instead of click

For further details, check the daisyUI Dropdown Documentation Full reference for CSS classes.

Example

Dropdown({
  label: "Menu",
  class: "dropdown-end dropdown-hover",
  items: menuItems
});
// Applies: right-aligned, opens on hover

Live Examples

Basic Dropdown (Items Array)

Live Demo

const BasicDemo = () => {
  return Dropdown({
    label: 'Options',
    items: [
      { label: 'Profile', onclick: () => Toast('Profile clicked', 'alert-info', 2000) },
      { label: 'Settings', onclick: () => Toast('Settings clicked', 'alert-info', 2000) },
      { label: 'Logout', onclick: () => Toast('Logged out', 'alert-warning', 2000), class: 'text-error' }
    ]
  });
};
$mount(BasicDemo, '#demo-basic');

With Icons (Items Array)

Live Demo

const IconsDemo = () => {
  return Dropdown({
    label: 'Menu',
    icon: '☰',
    items: [
      { icon: '👤', label: 'Profile', onclick: () => Toast('Profile', 'alert-info', 2000) },
      { icon: '⭐', label: 'Favorites', onclick: () => Toast('Favorites', 'alert-info', 2000) },
      { icon: '📁', label: 'Documents', onclick: () => Toast('Documents', 'alert-info', 2000) },
      { icon: '⚙️', label: 'Settings', onclick: () => Toast('Settings', 'alert-info', 2000) }
    ]
  });
};
$mount(IconsDemo, '#demo-icons');

Action Dropdown (Items Array)

Live Demo

const ActionsDemo = () => {
  const handleAction = (action) => {
    Toast(`${action} action`, 'alert-info', 2000);
  };
  
  return Dropdown({
    label: 'Actions',
    class: 'dropdown-end',
    items: [
      { icon: '✏️', label: 'Edit', onclick: () => handleAction('Edit') },
      { icon: '📋', label: 'Copy', onclick: () => handleAction('Copy') },
      { icon: '🗑️', label: 'Delete', onclick: () => handleAction('Delete'), class: 'text-error' }
    ]
  });
};
$mount(ActionsDemo, '#demo-actions');

User Dropdown (Items Array)

Live Demo

const UserDropdown = () => {
  return Dropdown({
    label: Span({ class: 'flex items-center gap-2' }, [
      Div({ class: 'avatar placeholder' }, [
        Div({ class: 'bg-primary text-primary-content rounded-full w-8 h-8 flex items-center justify-center text-sm' }, 'JD')
      ]),
      'John Doe'
    ]),
    class: 'dropdown-end',
    items: [
      { label: 'Profile', onclick: () => Toast('Profile', 'alert-info', 2000) },
      { label: 'Settings', onclick: () => Toast('Settings', 'alert-info', 2000) },
      { label: 'Sign Out', onclick: () => Toast('Signed out', 'alert-warning', 2000), class: 'text-error' }
    ]
  });
};
$mount(UserDropdown, '#demo-user');

Reactive Items

Live Demo

const ReactiveDropdown = () => {
  const count = $(0);
  
  const items = () => [
    { label: `Count: ${count()}`, onclick: () => {} },
    { label: 'Increment', onclick: () => count(count() + 1) },
    { label: 'Decrement', onclick: () => count(count() - 1) },
    { label: 'Reset', onclick: () => count(0) }
  ];
  
  return Dropdown({
    label: () => `Counter (${count()})`,
    items: items
  });
};
$mount(ReactiveDropdown, '#demo-reactive');

Notification Dropdown (Custom Children)

Live Demo

const NotificationsDropdown = () => {
  const notifications = $([
    { id: 1, title: 'New message', time: '5 min ago', read: false },
    { id: 2, title: 'Update available', time: '1 hour ago', read: false },
    { id: 3, title: 'Task completed', time: '2 hours ago', read: true }
  ]);
  
  const markAsRead = (id) => {
    notifications(notifications().map(n => 
      n.id === id ? { ...n, read: true } : n
    ));
  };
  
  const unreadCount = () => notifications().filter(n => !n.read).length;
  
  return Dropdown({
    label: Span({ class: 'relative' }, [
      '🔔',
      () => unreadCount() > 0 ? Span({ class: 'badge badge-xs badge-error absolute -top-1 -right-2' }, unreadCount()) : null
    ]),
    class: 'dropdown-end',
    children: () => Div({ class: 'w-80' }, [
      Div({ class: 'p-3 border-b border-base-300 font-bold' }, `Notifications (${unreadCount()} unread)`),
      Div({ class: 'max-h-64 overflow-y-auto' }, notifications().map(notif =>
        Div({ 
          class: `p-3 border-b border-base-300 cursor-pointer hover:bg-base-200 ${!notif.read ? 'bg-primary/5' : ''}`,
          onclick: () => markAsRead(notif.id)
        }, [
          Div({ class: 'font-medium' }, notif.title),
          Div({ class: 'text-xs opacity-60' }, notif.time),
          !notif.read && Span({ class: 'badge badge-xs badge-primary mt-1' }, 'New')
        ])
      )),
      Div({ class: 'p-2 text-center' }, [
        Button({ 
          class: 'btn btn-xs btn-ghost w-full',
          onclick: () => notifications([])
        }, 'Clear all')
      ])
    ])
  });
};
$mount(NotificationsDropdown, '#demo-notifications');

Custom Content Dropdown

Live Demo

const CustomDropdown = () => {
  const selected = $('Option 1');
  
  return Dropdown({
    label: () => selected(),
    children: () => Div({ class: 'p-4 min-w-48' }, [
      Div({ class: 'text-sm font-bold mb-2' }, 'Select an option'),
      Div({ class: 'flex flex-col gap-1' }, [
        Button({ 
          class: 'btn btn-ghost btn-sm justify-start',
          onclick: () => selected('Option 1')
        }, 'Option 1'),
        Button({ 
          class: 'btn btn-ghost btn-sm justify-start',
          onclick: () => selected('Option 2')
        }, 'Option 2'),
        Button({ 
          class: 'btn btn-ghost btn-sm justify-start',
          onclick: () => selected('Option 3')
        }, 'Option 3')
      ])
    ])
  });
};
$mount(CustomDropdown, '#demo-custom');

All Variants

Live Demo

const VariantsDemo = () => {
  const commonItems = [
    { label: 'Item 1', onclick: () => Toast('Item 1', 'alert-info', 2000) },
    { label: 'Item 2', onclick: () => Toast('Item 2', 'alert-info', 2000) },
    { label: 'Item 3', onclick: () => Toast('Item 3', 'alert-info', 2000) }
  ];
  
  return Div({ class: 'flex flex-wrap gap-4 justify-center' }, [
    Dropdown({ label: 'Default', items: commonItems }),
    Dropdown({ label: 'With Icon', icon: '☰', items: commonItems }),
    Dropdown({ label: 'End Position', class: 'dropdown-end', items: commonItems })
  ]);
};
$mount(VariantsDemo, '#demo-variants');