-
Notifications
You must be signed in to change notification settings - Fork 0
bug: CRITICAL - span-based dropdown toggles completely non-functional (Drupal compatibility) #15
Description
Description
CRITICAL BUG: When Drupal renders menu items without an href, it outputs <span> tags instead of <a> tags for dropdown toggles. These span-based dropdowns do not work at all - clicking them does nothing and the dropdown never opens.
Example HTML (from Drupal)
<li class="nav-item dropdown" role="none">
<span class="nav-link dropdown-toggle" id="productsLink" role="button"
data-bs-toggle="dropdown" aria-expanded="false">
Products
</span>
<ul class="dropdown-menu">...</ul>
</li>Symptoms
- Dropdown completely non-functional - Clicking the span-based toggle does absolutely nothing. The dropdown menu never opens.
- No pointer cursor -
<span>elements don't getcursor: pointerby default, giving no visual indication that it's clickable. - Missing keyboard accessibility - Span elements are not focusable without
tabindex="0".
Root Cause Analysis
1. No click handler for top-level span toggles
In src/js/enhanced-dropdowns.js, the _attachToggleHandlers() method (lines 134-142) only attaches click handlers for submenus, not top-level dropdowns:
_attachToggleHandlers(toggleElement, dropdownInstance, isSubmenu = false) {
this._attachKeyboardHandler(toggleElement, dropdownInstance);
// Add click handler only for submenus (top-level uses Bootstrap's native handling)
if (isSubmenu) {
this._attachClickHandler(toggleElement, dropdownInstance);
}
}Top-level dropdowns rely on Bootstrap's native click handling via initPopperConfig() (lines 194-206):
initPopperConfig() {
const existingToggles = document.querySelectorAll('[data-bs-toggle="dropdown"]');
existingToggles.forEach(toggle => {
if (bootstrap.Dropdown.getInstance(toggle)) return;
if (toggle.closest('.bs-dropdown-wrapper, .bs-dropdown-item-wrapper')) return;
const config = this._getPopperConfig(toggle);
new bootstrap.Dropdown(toggle, config); // Creates instance but no custom click handler
});
}Problem: Bootstrap's Dropdown component has issues with <span> elements - its internal event handling doesn't properly trigger for spans, even when the instance is created.
2. CSS doesn't apply cursor to spans
Bootstrap's CSS only sets cursor: pointer on a.dropdown-toggle and button.dropdown-toggle, not on generic .dropdown-toggle.
Proposed Fix
JavaScript fix (add click handler for span toggles):
initPopperConfig() {
const existingToggles = document.querySelectorAll('[data-bs-toggle="dropdown"]');
existingToggles.forEach(toggle => {
if (bootstrap.Dropdown.getInstance(toggle)) return;
if (toggle.closest('.bs-dropdown-wrapper, .bs-dropdown-item-wrapper')) return;
const config = this._getPopperConfig(toggle);
const dropdownInstance = new bootstrap.Dropdown(toggle, config);
// Add click handler for non-anchor/non-button toggles (e.g., spans from Drupal)
if (toggle.tagName !== 'A' && toggle.tagName !== 'BUTTON') {
toggle.addEventListener('click', () => dropdownInstance.toggle());
}
});
}CSS fix:
.nav-link.dropdown-toggle,
.dropdown-item.dropdown-toggle {
cursor: pointer;
}HTML requirement:
Ensure span toggles have tabindex="0" for keyboard accessibility.
Environment
- Bootstrap 5.3
- bs-enhanced-dropdowns 1.x
- Drupal CMS rendering menus with span elements for items without URLs
- Affects any system that renders dropdown toggles as spans instead of anchors