Home / playground / DROPDOWN_MENU_FIX

Dropdown Menu Example Fix

Problem

The Dropdown Menu example showed a button labeled "Actions" but when clicked, the dropdown menu was empty - no items were displayed.

Root Cause

The example was passing a simple string array to the items attribute:

// ❌ WRONG - Simple string array
'items': '["Edit", "Delete", "Share"]'

But the pan-dropdown component expects an array of objects with specific properties:

// ✅ CORRECT - Array of objects with label, value, icon
items: [
  { label: 'Edit', value: 'edit', icon: '✏️' },
  { label: 'Delete', value: 'delete', icon: '🗑️' },
  { label: 'Share', value: 'share', icon: '📤' }
]

Why It Failed

Looking at the component code (pan-dropdown.mjs, lines 255-269):

this.items.map(item => {
  if (item.divider) {
    return '<div class="dropdown-divider"></div>';
  }
  return `
    <div
      class="dropdown-item"
      data-value="${item.value || item.label}"
      ${item.disabled ? 'disabled' : ''}
    >
      ${item.icon ? `<span class="item-icon">${item.icon}</span>` : ''}
      ${item.label}  // ❌ undefined when item is a string
    </div>
  `;
}).join('')

When the component receives ["Edit", "Delete", "Share"]:

  • Each item is a string (e.g., "Edit")
  • item.label is undefined (strings don't have a .label property)
  • item.value is undefined
  • item.icon is undefined
  • Result: Empty divs with no text

Expected Item Format

From the component documentation (lines 1-14):

// Attributes:
//   - items: JSON array of menu items [{label, value, icon?, disabled?}]

Each item object can have:

  • label (required) - Display text for the menu item
  • value (optional) - Value sent in PAN message (defaults to label)
  • icon (optional) - Icon/emoji to display before label
  • disabled (optional) - Whether item is disabled
  • divider (special) - Shows a divider line instead of an item

Solution

Updated the example to use properly formatted item objects:

{
  id: 'dropdown-menu',
  name: 'Dropdown Menu',
  description: 'Dropdown with menu items',
  components: [
    {
      name: 'pan-dropdown',
      attributes: {
        'label': 'Actions',
        'topic': 'action.selected',
        'items': JSON.stringify([
          { label: 'Edit', value: 'edit', icon: '✏️' },
          { label: 'Delete', value: 'delete', icon: '🗑️' },
          { label: 'Share', value: 'share', icon: '📤' }
        ])
      }
    }
  ]
}

Why This Works

Now when the component renders:

  • item.label'Edit'
  • item.value'edit'
  • item.icon'✏️'
  • Result: Visible menu item with icon and text

Enhanced Features

The fix also adds icons to make the menu more visually appealing:

  • ✏️ Edit
  • 🗑️ Delete
  • 📤 Share

Example with Dividers and Disabled Items

You can also use more advanced features:

'items': JSON.stringify([
  { label: 'Edit', value: 'edit', icon: '✏️' },
  { label: 'Duplicate', value: 'duplicate', icon: '📋' },
  { divider: true },  // Adds a separator line
  { label: 'Delete', value: 'delete', icon: '🗑️', disabled: true },  // Grayed out
  { divider: true },
  { label: 'Share', value: 'share', icon: '📤' }
])

Testing

Before Fix

1. Load "Dropdown Menu" example
2. See: "Actions" button
3. Click button
4. See: Empty dropdown (no items) ❌

After Fix

1. Load "Dropdown Menu" example
2. See: "Actions" button
3. Click button
4. See: Dropdown with 3 items:
   - ✏️ Edit
   - 🗑️ Delete
   - 📤 Share
5. Click an item
6. PAN Monitor shows: action.selected.select { value: 'edit', label: 'Edit' }
7. Dropdown closes ✅

PAN Messages

When you click a menu item, the component publishes:

Topic: {topic}.select
Data: { value: 'edit', label: 'Edit' }

For the example:

  • Topic: action.selected.select
  • Data: { value: 'edit', label: 'Edit' }
You can also see:
  • action.selected.opened - When dropdown opens
  • action.selected.closed - When dropdown closes

Files Changed

/Users/cdr/Projects/larc-repos/playground/examples.mjs

Lines 425-429: Changed from string array to object array
// Before:
'items': '["Edit", "Delete", "Share"]'

// After:
'items': JSON.stringify([
  { label: 'Edit', value: 'edit', icon: '✏️' },
  { label: 'Delete', value: 'delete', icon: '🗑️' },
  { label: 'Share', value: 'share', icon: '📤' }
])

Component Registry Update Needed?

Let me check if the component registry has proper help text for the items attribute...

The component registry should document:

  • Items must be objects, not strings
  • Required: label
  • Optional: value, icon, disabled, divider
  • Example format

Related Components

Other components that might have similar issues with JSON attributes:

  • pan-tabs - Uses tabs attribute with array
  • drag-drop-list - Uses items attribute
  • Any component with complex JSON data

Key Takeaway

When a component expects JSON data via attributes:

  • Read the component documentation - Check the expected format
  • Use objects, not primitives - If it says {label, value}, use objects
  • Test with PAN Monitor - Verify the data structure in events
  • Check the render method - See what properties it accesses
  • Summary

    The dropdown menu example was fixed by changing the items attribute from a simple string array to an array of properly formatted objects with label, value, and icon properties. The dropdown now displays menu items correctly and publishes proper PAN events when items are selected.