<div class="n7-dropdown-menu">
    <button class="n7-dropdown-menu__trigger n7-dropdown-trigger group w-full flex items-center  font-medium hover:underline focus:n7-content-primary  aria-expanded:n7-background-02 lg:aria-expanded:bg-white aria-expanded:n7-content-01 p-3 gap-2 text-sm lg:text-base" aria-expanded="false" aria-controls="submenuId01">

        Menu item<svg class="n7-icon inline-block align-middle fill-current w-5 h-5 ml-auto transition-all n7-dropdown-menu__trigger-icon group-aria-expanded:-rotate-180" aria-hidden="true" focusable="false" role="img">
            <use href="../../icons.svg#mini--chevron-down" />
        </svg>
    </button>
    <ul class="n7-dropdown-menu__list hidden border border-t-0 n7-border-gray-01 w-full  lg:border-t lg:absolute lg:rounded lg:shadow-md" id="submenuId01">

        <li class="n7-dropdown-menu__item group border-b n7-border-gray-01 last-of-type:border-b-0">
            <a class="block p-3 transition bg-white text-sm xl:text-base hover:underline hover:n7-background-02 focus:n7-background-02 group-first:rounded-t group-last:rounded-b" href="">
                <div class="flex gap-2 items-center">

                    <svg class="n7-icon inline-block align-middle fill-current w-4 h-4 md:w-5 md:h-5 lg:w-6 lg:h-6 mr-2" aria-hidden="true" focusable="false" role="img">
                        <use href="../../icons.svg#solid--cube-transparent" />
                    </svg>

                    <span class="grow">Item label 1</span>

                </div>

            </a>
        </li>

        <li class="n7-dropdown-menu__item group border-b n7-border-gray-01 last-of-type:border-b-0">
            <a class="block p-3 transition bg-white text-sm xl:text-base hover:underline hover:n7-background-02 focus:n7-background-02 group-first:rounded-t group-last:rounded-b" href="">
                <div class="flex gap-2 items-center">

                    <span class="grow">Item label 3</span>

                    <svg class="n7-icon inline-block align-middle fill-current w-4 h-4 md:w-5 md:h-5 lg:w-6 lg:h-6 ml-2 transition-all duration-200 ease-out transform group-hover:translate-x-1" aria-hidden="true" focusable="false" role="img">
                        <use href="../../icons.svg#mini--chevron-right" />
                    </svg>

                </div>
                <div>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua</div>
            </a>
        </li>

        <li class="n7-dropdown-menu__item group border-b n7-border-gray-01 last-of-type:border-b-0">
            <a class="block p-3 transition bg-white text-sm xl:text-base hover:underline hover:n7-background-02 focus:n7-background-02 group-first:rounded-t group-last:rounded-b" href="">
                <div class="flex gap-2 items-center">

                    <svg class="n7-icon inline-block align-middle fill-current w-4 h-4 md:w-5 md:h-5 lg:w-6 lg:h-6 mr-2" aria-hidden="true" focusable="false" role="img">
                        <use href="../../icons.svg#solid--cube-transparent" />
                    </svg>

                    <span class="grow">Item label 4</span>

                    <svg class="n7-icon inline-block align-middle fill-current w-4 h-4 md:w-5 md:h-5 lg:w-6 lg:h-6 ml-2 transition-all duration-200 ease-out transform group-hover:translate-x-1" aria-hidden="true" focusable="false" role="img">
                        <use href="../../icons.svg#mini--chevron-right" />
                    </svg>

                </div>

            </a>
        </li>

        <li class="n7-dropdown-menu__item group border-b n7-border-gray-01 last-of-type:border-b-0">
            <a class="block p-3 transition bg-white text-sm xl:text-base hover:underline hover:n7-background-02 focus:n7-background-02 group-first:rounded-t group-last:rounded-b" href="">
                <div class="flex gap-2 items-center">

                    <span class="grow">Item label 5</span>

                </div>

            </a>
        </li>

    </ul>
</div>
<{% if listItem %}li{% else %}div{% endif %} class="n7-dropdown-menu{% if listItem %} has-dropdown-menu{% endif %}{% block classes %}{% if classes %} {{ classes }}{% endif %}{%- endblock classes -%}">
    <button class="n7-dropdown-menu__trigger n7-dropdown-trigger group w-full flex items-center {{ triggerTextColor }} font-medium hover:underline focus:n7-content-primary {% if triggerAriaExpandedStyles %} {{ triggerAriaExpandedStyles }}{% endif %}{% if triggerSpacing %} {{ triggerSpacing }}{% endif %}{% if triggerFontSize %} {{ triggerFontSize }}{% endif %}{% if triggerTextColor %} {{ triggerTextColor }}{% endif %}" aria-expanded="false" aria-controls="{{ id }}">
        {% if preContent %}
        {{ preContent | safe }}
        {% endif %}
        {{ label }} {%- render '@icon--small', {id: 'mini--chevron-down',size: 'w-5 h-5', classes: 'ml-auto transition-all n7-dropdown-menu__trigger-icon group-aria-expanded:-rotate-180'},true -%}
    </button>
    <ul class="n7-dropdown-menu__list hidden border border-t-0 n7-border-gray-01{% if listWidth %} {{ listWidth }}{% endif %} {% if listPosition %} {{ listPosition }}{% endif %}{% if listResponsiveStyles %} {{ listResponsiveStyles }}{% endif %}{% if listClasses %} {{ listClasses }}{% endif %}" id="{{ id }}">
        {% for item in items %}
        <li class="n7-dropdown-menu__item group border-b n7-border-gray-01 last-of-type:border-b-0{% if listItemClasses %} {{ listItemClasses }} {% endif %}">
            <a class="block p-3 transition bg-white{% if dropdownItemFontSize %} {{ dropdownItemFontSize }}{% endif %} hover:underline hover:n7-background-02 focus:n7-background-02 group-first:rounded-t group-last:rounded-b" href="">
                <div class="flex gap-2 items-center">
                    {% if item.iconLeft %}
                        {% render '@icon--small', { id: item.iconLeft, classes: 'mr-2', size: 'w-4 h-4 md:w-5 md:h-5 lg:w-6 lg:h-6' }, true %}
                    {% endif %}
                    <span class="grow">{% if item.label %}{{ item.label }}{% else %} Item {% endif %}</span>
                    {% if item.iconRight %}
                        {% render '@icon--small', { id: item.iconRight, classes: 'ml-2 transition-all duration-200 ease-out transform group-hover:translate-x-1', size: 'w-4 h-4 md:w-5 md:h-5 lg:w-6 lg:h-6' }, true %}
                    {% endif %}
                </div>
                {% if item.description %}<div>{{ item.description }}</div>{% endif %}
            </a>
        </li>
        {% endfor %}
    </ul>
</{% if listItem %}li{% else %}div{% endif %}>
{
  "label": "Menu item",
  "id": "submenuId01",
  "triggerSpacing": "p-3 gap-2",
  "triggerFontSize": "text-sm lg:text-base",
  "dropdownItemFontSize": "text-sm xl:text-base",
  "listResponsiveStyles": "lg:border-t lg:absolute lg:rounded lg:shadow-md",
  "triggerAriaExpandedStyles": "aria-expanded:n7-background-02 lg:aria-expanded:bg-white aria-expanded:n7-content-01",
  "items": [
    {
      "label": "Item label 1",
      "iconLeft": "solid--cube-transparent"
    },
    {
      "label": "Item label 3",
      "description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua",
      "iconRight": "mini--chevron-right"
    },
    {
      "label": "Item label 4",
      "iconLeft": "solid--cube-transparent",
      "iconRight": "mini--chevron-right"
    },
    {
      "label": "Item label 5"
    }
  ]
}
  • Content:
    /**
     * DROPDOWN MENU
     */
    @layer components {
      /* TODO: MOVE STYLE TO TAILWIND CLASS? */
      .n7-dropdown-menu__list[style*="block"] {
        @apply z-10;
      }
    }
    
    @layer components {
      .n7-dropdown-trigger[aria-expanded="true"] .n7-dropdown-menu__trigger-icon {
        @apply -rotate-180;
      }
      
      .n7-megamenu-trigger[aria-expanded="true"] [data-dropdown-icon] {
        @apply rotate-90;
      }
      
      .n7-dropdown-menu__list {
        transition: opacity 0.2s ease-in-out;
      }
      
      .n7-megamenu-submenu {
        transition: opacity 0.2s ease-in-out;
      }
    
      /* ==========================================================================
         POSIZIONAMENTO INTELLIGENTE
         ========================================================================== */
      
      /* Allineamento orizzontale */
      .align-right {
        @apply right-0 left-auto;
      }
      
      .align-left {
        @apply left-0 right-auto;
      }
      
      /* Forzatura quando non c'è spazio */
      .force-right {
        right: 0 !important;
        left: auto !important;
      }
      
      /* Posizionamento verticale per sottomenu */
      .open-upward {
        @apply bottom-full top-auto;
      }
      
      .open-downward {
        @apply top-full bottom-auto;
      }
    }
  • URL: /components/raw/dropdown-menu/dropdown-menu.css
  • Filesystem Path: components/03-molecules/dropdown-menu/dropdown-menu.css
  • Size: 1.1 KB
  • Content:
    /*
     * JavaScript per supportare sia dropdown semplici che megamenu
     */
    
    'use strict';
    
    function findAncestor(element, tagName) {
      while (element) {
        if (element.tagName.toLowerCase() === tagName) {
          return element;
        }
        element = element.parentElement;
      }
      return null;
    }
    
    function getTabbableElements(container) {
      return container.querySelectorAll(
        'a[href], button:not([disabled]), textarea:not([disabled]), input:not([type="hidden"]):not([disabled]), select:not([disabled]), [tabindex]:not([tabindex="-1"])'
      );
    }
    
    // Funzione per calcolare la posizione PRIMA di mostrare il menu
    function calculateOptimalPosition(menu, trigger) {
      // Rimuovi classi precedenti
      menu.classList.remove('align-right', 'align-left', 'force-right');
      
      // Rendi il menu temporaneamente visibile ma invisibile per misurarlo
      const wasHidden = menu.classList.contains('hidden');
      menu.classList.remove('hidden');
      menu.style.visibility = 'hidden';
      menu.style.opacity = '0';
      
      // Misura immediatamente
      const menuRect = menu.getBoundingClientRect();
      const viewportWidth = window.innerWidth;
      
      let positionClass = null;
      
      // Se il menu esce a destra
      if (menuRect.right > viewportWidth - 10) {
        positionClass = 'align-right';
        
        // Test se con align-right va ancora fuori
        menu.classList.add('align-right');
        const testRect = menu.getBoundingClientRect();
        if (testRect.right > viewportWidth - 10) {
          positionClass = 'force-right';
          menu.classList.remove('align-right');
          menu.classList.add('force-right');
        }
      }
      // Se il menu esce a sinistra
      else if (menuRect.left < 10) {
        positionClass = 'align-left';
        menu.classList.add('align-left');
      }
      
      // Nascondilo di nuovo se era nascosto
      if (wasHidden) {
        menu.classList.add('hidden');
      }
      menu.style.visibility = '';
      menu.style.opacity = '';
      
      return positionClass;
    }
    
    class DisclosureNav {
      constructor(domNode) {
        this.rootNode = domNode;
        this.controlledNodes = [];
        this.openIndex = null;
        this.useArrowKeys = true;
        this.isClosing = false;
        
        this.topLevelNodes = [
          ...this.rootNode.querySelectorAll(
            '.main-link, .rtds-dropdown-trigger, .n7-dropdown-menu__trigger, .n7-dropdown-trigger, .n7-primary-navigation__link'
          ),
        ];
    
        this.topLevelNodes.forEach((node, index) => {
          if (
            node.tagName.toLowerCase() === 'button' &&
            node.hasAttribute('aria-controls')
          ) {
            const menu = node.parentNode.querySelector('ul, div.n7-dropdown-menu__list');
    
            if (menu) {
              this.controlledNodes.push(menu);
    
              node.setAttribute('aria-expanded', 'false');
              this.toggleMenu(menu, false);
    
              menu.addEventListener('keydown', this.onMenuKeyDown.bind(this));
              node.addEventListener('click', this.onButtonClick.bind(this));
              node.addEventListener('keydown', this.onButtonKeyDown.bind(this));
            }
          } else {
            this.controlledNodes.push(null);
            node.addEventListener('keydown', this.onLinkKeyDown.bind(this));
          }
        });
    
        document.addEventListener('click', this.onDocumentClick.bind(this));
        document.addEventListener('keydown', this.onGlobalKeyDown.bind(this));
        window.addEventListener('resize', this.onWindowResize.bind(this));
      }
    
      onWindowResize() {
        if (this.openIndex !== null) {
          const menu = this.controlledNodes[this.openIndex];
          const trigger = this.topLevelNodes[this.openIndex];
          if (menu && trigger) {
            calculateOptimalPosition(menu, trigger);
          }
        }
      }
    
      focusElement(element, delay = 50) {
        if (!element || typeof element.focus !== 'function') return;
        
        setTimeout(() => {
          try {
            element.focus();
          } catch (e) {
            console.warn('Focus failed:', e);
          }
        }, delay);
      }
    
      onGlobalKeyDown(event) {
        if (event.key !== 'Tab' || this.openIndex === null || this.isClosing) {
          return;
        }
    
        const openMenu = this.controlledNodes[this.openIndex];
        if (!openMenu) return;
    
        const activeElement = document.activeElement;
        
        // Se siamo in un sottomenu del megamenu, lascia che MegaMenuSubmenu lo gestisca
        const isInSubmenu = activeElement.closest('[data-dropdown-content]');
        if (isInSubmenu && !isInSubmenu.classList.contains('hidden')) {
          return;
        }
    
        // Gestisci gli elementi tabbabili del menu
        let allTabbableInMenu;
        
        if (openMenu.classList.contains('n7-dropdown-menu__list')) {
          // Per megamenu: escludi elementi in sottomenu chiusi
          allTabbableInMenu = Array.from(getTabbableElements(openMenu)).filter(el => {
            const hiddenSubmenu = el.closest('[data-dropdown-content].hidden');
            return !hiddenSubmenu;
          });
        } else {
          // Per dropdown semplice: prendi tutti
          allTabbableInMenu = Array.from(getTabbableElements(openMenu));
        }
        
        const currentIndex = allTabbableInMenu.indexOf(activeElement);
        
        if (!event.shiftKey && currentIndex === allTabbableInMenu.length - 1) {
          // Tab sull'ultimo elemento del menu - resta sul trigger
          event.preventDefault();
          const currentTrigger = this.topLevelNodes[this.openIndex];
          this.closeMenu();
          this.focusElement(currentTrigger);
        }
        else if (event.shiftKey && currentIndex === 0) {
          // Shift+Tab sul primo elemento del menu
          event.preventDefault();
          this.closeMenuAndFocusTrigger();
        }
      }
    
      closeMenu() {
        if (this.openIndex === null || this.isClosing) return;
        
        this.isClosing = true;
        
        this.topLevelNodes[this.openIndex].setAttribute('aria-expanded', 'false');
        this.toggleMenu(this.controlledNodes[this.openIndex], false);
        this.openIndex = null;
        
        setTimeout(() => {
          this.isClosing = false;
        }, 100);
      }
    
      closeMenuAndFocusTrigger() {
        if (this.openIndex === null || this.isClosing) return;
        
        const trigger = this.topLevelNodes[this.openIndex];
        this.closeMenu();
        this.focusElement(trigger);
      }
    
      controlFocusByKey(keyboardEvent, nodeList, currentIndex) {
        switch (keyboardEvent.key) {
          case 'ArrowUp':
          case 'ArrowLeft':
            keyboardEvent.preventDefault();
            if (currentIndex > -1) {
              var prevIndex = Math.max(0, currentIndex - 1);
              nodeList[prevIndex].focus();
            }
            break;
          case 'ArrowDown':
          case 'ArrowRight':
            keyboardEvent.preventDefault();
            if (currentIndex > -1) {
              var nextIndex = Math.min(nodeList.length - 1, currentIndex + 1);
              nodeList[nextIndex].focus();
            }
            break;
          case 'Home':
            keyboardEvent.preventDefault();
            nodeList[0].focus();
            break;
          case 'End':
            keyboardEvent.preventDefault();
            nodeList[nodeList.length - 1].focus();
            break;
        }
      }
    
      close() {
        this.closeMenu();
      }
    
      onButtonClick(event) {
        if (this.isClosing) return;
        
        var target = event.target;
    
        if (target.tagName.toLowerCase() !== 'button') {
          var buttonAncestor = findAncestor(target, 'button');
          if (buttonAncestor) {
            buttonAncestor.click();
            return;
          }
        }
    
        var button = event.target;
        var buttonIndex = this.topLevelNodes.indexOf(button);
        var buttonExpanded = button.getAttribute('aria-expanded') === 'true';
        
        this.toggleExpand(buttonIndex, !buttonExpanded);
      }
    
      onButtonKeyDown(event) {
        if (this.isClosing) return;
        
        var targetButtonIndex = this.topLevelNodes.indexOf(document.activeElement);
    
        if (event.key === 'Escape') {
          event.preventDefault();
          this.closeMenuAndFocusTrigger();
        } else if (
          this.useArrowKeys &&
          this.openIndex === targetButtonIndex &&
          event.key === 'ArrowDown'
        ) {
          event.preventDefault();
          const menu = this.controlledNodes[this.openIndex];
          const firstTabbable = getTabbableElements(menu)[0];
          if (firstTabbable) {
            firstTabbable.focus();
          }
        } else if (this.useArrowKeys) {
          this.controlFocusByKey(event, this.topLevelNodes, targetButtonIndex);
        }
      }
    
      onLinkKeyDown(event) {
        var targetLinkIndex = this.topLevelNodes.indexOf(document.activeElement);
    
        if (this.useArrowKeys) {
          this.controlFocusByKey(event, this.topLevelNodes, targetLinkIndex);
        }
      }
    
      onMenuKeyDown(event) {
        if (this.openIndex === null || this.isClosing) {
          return;
        }
    
        if (event.key === 'Escape') {
          event.preventDefault();
          event.stopImmediatePropagation();
          this.closeMenuAndFocusTrigger();
          return;
        }
    
        var menuFocusables = Array.from(getTabbableElements(this.controlledNodes[this.openIndex]));
        var currentIndex = menuFocusables.indexOf(document.activeElement);
    
        if (this.useArrowKeys) {
          this.controlFocusByKey(event, menuFocusables, currentIndex);
        }
      }
    
      toggleExpand(index, expanded) {
        if (this.isClosing) return;
        
        if (this.openIndex !== null && this.openIndex !== index) {
          this.closeMenu();
        }
    
        if (this.topLevelNodes[index]) {
          this.openIndex = expanded ? index : null;
          this.topLevelNodes[index].setAttribute('aria-expanded', expanded);
          this.toggleMenu(this.controlledNodes[index], expanded);
        }
      }
    
      toggleMenu(domNode, show) {
        if (!domNode) return;
        
        const isMegaMenu = domNode.classList.contains('n7-dropdown-menu__list');
        const parentMenu = domNode.closest('.has-dropdown-menu, .n7-dropdown-menu');
        const navModule = domNode.closest('.rtds-primary-navigation__module');
    
        if (show) {
          // Calcola la posizione PRIMA di mostrare il menu
          const trigger = this.topLevelNodes[this.openIndex];
          if (trigger) {
            calculateOptimalPosition(domNode, trigger);
          }
          
          // Ora mostra il menu con la posizione già corretta
          if (isMegaMenu) {
            domNode.classList.remove('hidden');
            domNode.classList.add('block');
          } else {
            domNode.classList.remove('rtds-hidden', 'is-hidden');
            domNode.classList.add('is-open');
          }
          
          if (parentMenu) {
            parentMenu.classList.add('has-dropdown-open');
          }
          if (navModule) {
            navModule.classList.add('has-inner-dropdown-open');
          }
          
        } else {
          if (isMegaMenu) {
            domNode.classList.remove('block');
            domNode.classList.add('hidden');
          } else {
            domNode.classList.remove('is-open');
            domNode.classList.add('rtds-hidden');
          }
          
          if (parentMenu) {
            parentMenu.classList.remove('has-dropdown-open');
          }
          if (navModule) {
            navModule.classList.remove('has-inner-dropdown-open');
          }
    
          domNode.classList.remove('align-right', 'align-left', 'force-right', 'open-upward', 'open-downward');
        }
      }
    
      updateKeyControls(useArrowKeys) {
        this.useArrowKeys = useArrowKeys;
      }
    
      onDocumentClick(event) {
        if (this.rootNode.contains(event.target) || this.isClosing) {
          return;
        }
        
        this.closeMenu();
      }
    }
    
    class MegaMenuSubmenu {
      constructor() {
        this.openSubmenus = new Map();
        this.isClosing = false;
        this.init();
      }
    
      focusElement(element, delay = 50) {
        if (!element || typeof element.focus !== 'function') return;
        
        setTimeout(() => {
          try {
            element.focus();
          } catch (e) {
            console.warn('Submenu focus failed:', e);
          }
        }, delay);
      }
    
      init() {
        const megaMenuTriggers = document.querySelectorAll('[data-dropdown-trigger]');
        
        megaMenuTriggers.forEach(trigger => {
          trigger.addEventListener('click', this.handleSubmenuClick.bind(this));
          trigger.addEventListener('keydown', this.handleSubmenuKeydown.bind(this));
        });
    
        document.addEventListener('keydown', this.onGlobalKeyDown.bind(this));
        window.addEventListener('resize', this.onWindowResize.bind(this));
      }
    
      onWindowResize() {
        this.openSubmenus.forEach((submenu, trigger) => {
          calculateOptimalPosition(submenu, trigger);
        });
      }
    
      onGlobalKeyDown(event) {
        if (event.key !== 'Tab' || this.isClosing) {
          return;
        }
    
        const activeElement = document.activeElement;
        const submenu = activeElement.closest('[data-dropdown-content]');
        
        // Solo per sottomenu di megamenu, non per dropdown normali
        if (submenu && !submenu.classList.contains('hidden') && submenu.closest('.n7-dropdown-menu__list')) {
          const trigger = submenu.parentElement.querySelector('[data-dropdown-trigger]');
          if (!trigger) return;
    
          const tabbableElements = getTabbableElements(submenu);
          const currentIndex = Array.from(tabbableElements).indexOf(activeElement);
          
          if (!event.shiftKey && currentIndex === tabbableElements.length - 1) {
            event.preventDefault();
            this.closeSubmenuAndFocusTrigger(trigger);
          }
          else if (event.shiftKey && currentIndex === 0) {
            event.preventDefault();
            this.closeSubmenuAndFocusTrigger(trigger);
          }
        }
      }
    
      closeSubmenu(trigger) {
        const submenu = trigger.parentElement.querySelector('[data-dropdown-content]');
        const icon = trigger.querySelector('[data-dropdown-icon]');
        
        if (submenu) {
          this.isClosing = true;
          this.toggleSubmenu(trigger, submenu, icon, false);
          setTimeout(() => {
            this.isClosing = false;
          }, 100);
        }
      }
    
      closeSubmenuAndFocusTrigger(trigger) {
        this.closeSubmenu(trigger);
        this.focusElement(trigger);
      }
    
      handleSubmenuClick(event) {
        if (this.isClosing) return;
        
        event.preventDefault();
        event.stopPropagation();
        
        const trigger = event.currentTarget;
        const submenu = trigger.parentElement.querySelector('[data-dropdown-content]');
        const icon = trigger.querySelector('[data-dropdown-icon]');
        
        if (!submenu) return;
    
        const isExpanded = trigger.getAttribute('aria-expanded') === 'true';
        
        this.closeOtherSubmenus(trigger);
        this.toggleSubmenu(trigger, submenu, icon, !isExpanded);
      }
    
      handleSubmenuKeydown(event) {
        if (this.isClosing) return;
        
        const trigger = event.currentTarget;
        const submenu = trigger.parentElement.querySelector('[data-dropdown-content]');
        const icon = trigger.querySelector('[data-dropdown-icon]');
    
        if (event.key === 'Enter' || event.key === ' ') {
          event.preventDefault();
          this.handleSubmenuClick(event);
        } else if (event.key === 'Escape') {
          event.preventDefault();
          this.closeSubmenuAndFocusTrigger(trigger);
        } else if (event.key === 'ArrowDown' && trigger.getAttribute('aria-expanded') === 'true') {
          event.preventDefault();
          const firstTabbable = getTabbableElements(submenu)[0];
          if (firstTabbable) {
            firstTabbable.focus();
          }
        }
      }
    
      toggleSubmenu(trigger, submenu, icon, show) {
        trigger.setAttribute('aria-expanded', show);
        
        if (show) {
          // Calcola la posizione PRIMA di mostrare il sottomenu
          calculateOptimalPosition(submenu, trigger);
          
          // Ora mostra il sottomenu con la posizione già corretta
          submenu.classList.remove('hidden');
          submenu.classList.add('block');
          this.openSubmenus.set(trigger, submenu);
          if (icon) {
            icon.style.transform = 'rotate(90deg)';
          }
          
        } else {
          submenu.classList.remove('block');
          submenu.classList.add('hidden');
          this.openSubmenus.delete(trigger);
          if (icon) {
            icon.style.transform = 'rotate(0deg)';
          }
    
          submenu.classList.remove('align-right', 'align-left', 'force-right', 'open-upward', 'open-downward');
        }
      }
    
      closeOtherSubmenus(currentTrigger) {
        const megaMenu = currentTrigger.closest('.n7-dropdown-menu__list');
        if (!megaMenu) return;
    
        const allTriggers = megaMenu.querySelectorAll('[data-dropdown-trigger]');
        
        allTriggers.forEach(trigger => {
          if (trigger !== currentTrigger) {
            const submenu = trigger.parentElement.querySelector('[data-dropdown-content]');
            const icon = trigger.querySelector('[data-dropdown-icon]');
            
            if (submenu) {
              this.toggleSubmenu(trigger, submenu, icon, false);
            }
          }
        });
      }
    
      closeAllSubmenus() {
        this.openSubmenus.forEach((submenu, trigger) => {
          const icon = trigger.querySelector('[data-dropdown-icon]');
          this.toggleSubmenu(trigger, submenu, icon, false);
        });
      }
    }
    
    window.addEventListener(
      'load',
      function () {
        var menus = document.querySelectorAll('.has-dropdown-menu, div.rtds-dropdown-menu, .n7-dropdown-menu[class*="has-dropdown-menu"], .n7-dropdown-menu');
        var disclosureMenus = [];
        var processedPrimaryNavs = new Set();
        
        for (var i = 0; i < menus.length; i++) {
          const menu = menus[i];
          
          // Se è dentro un primary navigation
          const primaryNav = menu.closest('.n7-primary-navigation');
          if (primaryNav) {
            // Se non abbiamo già processato questo primary navigation
            if (!processedPrimaryNavs.has(primaryNav)) {
              processedPrimaryNavs.add(primaryNav);
              
              // Inizializza sul modulo principale che contiene tutti i menu
              const mainModule = primaryNav.querySelector('.n7-primary-navigation__module');
              if (mainModule) {
                disclosureMenus.push(new DisclosureNav(mainModule));
              }
            }
          } else {
            // Menu standalone (non in primary navigation)
            disclosureMenus.push(new DisclosureNav(menu));
          }
        }
    
        new MegaMenuSubmenu();
      },
      false
    );
  • URL: /components/raw/dropdown-menu/dropdown-menu.js
  • Filesystem Path: components/03-molecules/dropdown-menu/dropdown-menu.js
  • Size: 17.6 KB

Dropdown menu component can be used as a dropdown indipendent component (has div as wrapper) or as a list item in a menu list - list-item variant (eg in primary menu).

In preview, component style is missing - this component is dependant on list/menu in which is used.

  • listItem: boolean - if true, the component is used as list item in a menu list, otherwise as a dropdown indipendendt component as is
  • id: value - dropdown id
  • classes: value - add eventual classes
  • triggerSpacing: value - spacing classes for trigger button
  • triggerFontSize: value - font size classes for trigger button
  • triggerTextColor: valie - trigger text color class if needed
  • label: value - dropdown main label (trigger label)
  • listPosition: value - position of the dropdown list - eventually manage left and right position od dropdown list
  • listResponsiveStyles: value - manage responsive styles of dropdown list if needed
  • listWidth: value - width of the dropdown list
  • listClasses: value - classes for dropdown list
  • listItemClasses: value: classes for dropdown list items (li elements)
  • dropdownItemFontSize: value - classes for items font size
  • items:
    • iconLeft: value - id for item left icon
    • label: value - item label
    • iconRight: value - id for item right icon
    • description: value - item description

Blocks:

  • preContent: used eg for user thumb or icon if needed
  • classes: for class overridings in variant templates, if needed