<li class="rtds-dropdown-menu has-dropdown-menu has-megamenu">
    <button class="rtds-dropdown-menu__trigger rtds-dropdown-trigger rtds-group rtds-w-full rtds-flex rtds-items-center  aria-expanded:rtds-sticky aria-expanded:rtds-z-30 aria-expanded:rtds-top-0 aria-expanded:rtds-bg-white aria-expanded:rtds-content-primary aria-expanded:rtds-border-b-4 aria-expanded:rtds-border-gray-02 lg:aria-expanded:rtds-border-b-0 rtds-p-3 rtds-gap-2 rtds-text-sm lg:rtds-text-base" aria-expanded="false" aria-controls="submenuId01">

        Menu item

        <svg class="rtds-icon rtds-fill-current rtds-w-8 rtds-h-8 lg:rtds-hidden rtds-ml-auto rtds-transition-all rtds-dropdown-menu__trigger-icon group-aria-expanded:-rtds-rotate-180" aria-hidden="true" focusable="false" role="img">
            <use href="../../icons.svg#mini--chevron-right" />
        </svg>
        <svg class="rtds-icon rtds-fill-current rtds-w-5 rtds-h-5 rtds-hidden lg:rtds-inline-flex rtds-ml-auto rtds-transition-all rtds-dropdown-menu__trigger-icon group-aria-expanded:-rtds-rotate-180" aria-hidden="true" focusable="false" role="img">
            <use href="../../icons.svg#mini--chevron-down" />
        </svg>

    </button>

    <div class="rtds-dropdown-menu__megamenu lg:rtds-top-[--header-offset]  rtds-w-full lg:rtds-absolute lg:rtds-shadow-md lg:rtds-p-8" id="submenuId01">
        <ul class="rtds-dropdown-menu__list lg:rtds-container">

            <li class="rtds-dropdown-menu__item rtds-group/menu-item">
                <a class="rtds-dropdown-menu__link rtds-block rtds-transition" href="">
                    <div class="rtds-flex rtds-gap-2 rtds-items-center">

                        <span class="rtds-grow">List item</span>

                    </div>

                </a>
            </li>

            <li class="rtds-dropdown-menu__item rtds-group/menu-item">
                <a class="rtds-dropdown-menu__link rtds-block rtds-transition" href="">
                    <div class="rtds-flex rtds-gap-2 rtds-items-center">

                        <span class="rtds-grow">List item</span>

                    </div>

                </a>
            </li>

            <li class="rtds-dropdown-menu__item rtds-group/menu-item">
                <a class="rtds-dropdown-menu__link rtds-block rtds-transition" href="">
                    <div class="rtds-flex rtds-gap-2 rtds-items-center">

                        <span class="rtds-grow">List item</span>

                    </div>

                </a>
            </li>

            <li class="rtds-dropdown-menu__item rtds-group/menu-item">
                <a class="rtds-dropdown-menu__link rtds-block rtds-transition" href="">
                    <div class="rtds-flex rtds-gap-2 rtds-items-center">

                        <span class="rtds-grow">List item</span>

                    </div>

                </a>
            </li>

            <li class="rtds-dropdown-menu__item rtds-group/menu-item">
                <a class="rtds-dropdown-menu__link rtds-block rtds-transition" href="">
                    <div class="rtds-flex rtds-gap-2 rtds-items-center">

                        <span class="rtds-grow">List item</span>

                    </div>

                </a>
            </li>

            <li class="rtds-dropdown-menu__item rtds-group/menu-item">
                <a class="rtds-dropdown-menu__link rtds-block rtds-transition" href="">
                    <div class="rtds-flex rtds-gap-2 rtds-items-center">

                        <span class="rtds-grow">List item</span>

                    </div>

                </a>
            </li>

            <li class="rtds-dropdown-menu__item rtds-group/menu-item">
                <a class="rtds-dropdown-menu__link rtds-block rtds-transition" href="">
                    <div class="rtds-flex rtds-gap-2 rtds-items-center">

                        <span class="rtds-grow">List item</span>

                    </div>

                </a>
            </li>

            <li class="rtds-dropdown-menu__item rtds-group/menu-item">
                <a class="rtds-dropdown-menu__link rtds-block rtds-transition" href="">
                    <div class="rtds-flex rtds-gap-2 rtds-items-center">

                        <span class="rtds-grow">List item</span>

                    </div>

                </a>
            </li>

            <li class="rtds-dropdown-menu__item rtds-group/menu-item">
                <a class="rtds-dropdown-menu__link rtds-block rtds-transition" href="">
                    <div class="rtds-flex rtds-gap-2 rtds-items-center">

                        <span class="rtds-grow">List item</span>

                    </div>

                </a>
            </li>

            <li class="rtds-dropdown-menu__item rtds-group/menu-item">
                <a class="rtds-dropdown-menu__link rtds-block rtds-transition" href="">
                    <div class="rtds-flex rtds-gap-2 rtds-items-center">

                        <span class="rtds-grow">List item</span>

                    </div>

                </a>
            </li>

            <li class="rtds-dropdown-menu__item rtds-group/menu-item">
                <a class="rtds-dropdown-menu__link rtds-block rtds-transition" href="">
                    <div class="rtds-flex rtds-gap-2 rtds-items-center">

                        <span class="rtds-grow">List item</span>

                    </div>

                </a>
            </li>

            <li class="rtds-dropdown-menu__item rtds-group/menu-item">
                <a class="rtds-dropdown-menu__link rtds-block rtds-transition" href="">
                    <div class="rtds-flex rtds-gap-2 rtds-items-center">

                        <span class="rtds-grow">List item</span>

                    </div>

                </a>
            </li>

        </ul>
    </div>

</li>
{% extends '@dropdown-menu' %}
{% block classes %}{{ super() }} has-megamenu{% endblock classes %}
{% block triggerIcon %}
    {%- render '@icon--small', {id: 'mini--chevron-right',size: 'rtds-w-8 rtds-h-8', classes: 'lg:rtds-hidden rtds-ml-auto rtds-transition-all rtds-dropdown-menu__trigger-icon group-aria-expanded:-rtds-rotate-180'},true -%}
    {%- render '@icon--small', {id: 'mini--chevron-down',size: 'rtds-w-5 rtds-h-5', classes: 'rtds-hidden lg:rtds-inline-flex rtds-ml-auto rtds-transition-all rtds-dropdown-menu__trigger-icon group-aria-expanded:-rtds-rotate-180'},true -%}
{% endblock triggerIcon %}

{% block listStart %}
<div class="rtds-dropdown-menu__megamenu lg:rtds-top-[--header-offset] {% if listWidth %} {{ listWidth }}{% endif %}{% if listPosition %} {{ listPosition }}{% endif %}{% if listResponsiveStyles %} {{ listResponsiveStyles }}{% endif %}{% if listClasses %} {{ listClasses }}{% endif %}" id="{{ id }}">
    <ul class="rtds-dropdown-menu__list lg:rtds-container">
{% endblock listStart %}

{% block listEnd %}
    </ul>
</div> 
{% endblock listEnd %}
{
  "label": "Menu item",
  "id": "submenuId01",
  "triggerSpacing": "rtds-p-3 rtds-gap-2",
  "triggerFontSize": "rtds-text-sm lg:rtds-text-base",
  "triggerAriaExpandedStyles": "aria-expanded:rtds-sticky aria-expanded:rtds-z-30 aria-expanded:rtds-top-0 aria-expanded:rtds-bg-white aria-expanded:rtds-content-primary aria-expanded:rtds-border-b-4 aria-expanded:rtds-border-gray-02 lg:aria-expanded:rtds-border-b-0",
  "items": [
    {
      "label": "List item"
    },
    {
      "label": "List item"
    },
    {
      "label": "List item"
    },
    {
      "label": "List item"
    },
    {
      "label": "List item"
    },
    {
      "label": "List item"
    },
    {
      "label": "List item"
    },
    {
      "label": "List item"
    },
    {
      "label": "List item"
    },
    {
      "label": "List item"
    },
    {
      "label": "List item"
    },
    {
      "label": "List item"
    }
  ],
  "listItem": true,
  "listWidth": "rtds-w-full",
  "listResponsiveStyles": "lg:rtds-absolute lg:rtds-shadow-md lg:rtds-p-8"
}
  • Content:
    /**
     * DROPDOWN MENU
     *
    */
    @layer components {
        /* DROPDOWN MENU STYLES */
        .rtds-dropdown-menu__list[style*="block"] {
            @apply rtds-z-10;
        }
    
        .rtds-dropdown-menu__list,
        .rtds-dropdown-menu__item {
            @apply rtds-border-gray-01;
        }
    
        .rtds-dropdown-menu__list:where(.is-open) {
            @apply lg:rtds-top-full;
        }
    
        .rtds-dropdown-menu__item {
            @apply rtds-border-b last-of-type:rtds-border-b-0;
        }
    
        .rtds-dropdown-menu__link {
            @apply rtds-p-3 rtds-bg-white hover:rtds-underline hover:rtds-background-02 focus:rtds-background-02;
        }
    
        /* DROPDOWN TRIGGER */
        .rtds-dropdown-menu__trigger[aria-expanded="true"] {
            @apply after:rtds-absolute after:rtds-block after:rtds-bg-transparent after:rtds-border-t-2 after:rtds-border-current after:rtds-h-[1px] after:rtds-w-full after:rtds-left-0 after:rtds-bottom-0;
        }
    
        /* ACTIONS VARIANT STYLES */
        .is-dropdown-menu--actions {
            @apply rtds-flex rtds-justify-end rtds-relative;
        }
    
        .is-dropdown-menu--actions .rtds-dropdown-menu__trigger {
            @apply rtds-rounded-full rtds-border rtds-border-gray-04 rtds-w-10 rtds-h-10 rtds-content-01 rtds-btn--inverted rtds-transition-all;
        }
    
        .is-dropdown-menu--actions .rtds-dropdown-menu__trigger[aria-expanded="true"] {
            @apply rtds-background-08 rtds-content-inverse;
        }
    
        .is-dropdown-menu--actions .rtds-dropdown-menu__list {
            @apply rtds-w-[25ch] rtds-absolute rtds-right-0 rtds-top-10 rtds-bg-white rtds-shadow-lg rtds-z-10 rtds-rounded rtds-border rtds-border-gray-01;
        }
    
        .is-dropdown-menu--actions .rtds-dropdown-menu__item {
            @apply rtds-flex rtds-border-none;
        }
    
        .is-dropdown-menu--actions .rtds-dropdown-menu__link {
            @apply rtds-flex rtds-justify-start rtds-gap-2 rtds-items-center rtds-p-3 rtds-btn--s rtds-w-full rtds-transition rtds-bg-white rtds-font-medium rtds-text-sm rtds-content-primary-dark hover:rtds-underline hover:rtds-background-02 focus:rtds-background-02;
        }
    
        /* MEGAMENU STYLES */
        .rtds-dropdown-menu__megamenu.is-open {
            @apply lg:rtds-background-02;
        }
    
        .has-megamenu .rtds-dropdown-menu__item {
            @apply rtds-border-dashed rtds-border-gray-03 last-of-type:rtds-border-b rtds-font-bold;
        }
    
        .has-megamenu .rtds-dropdown-menu__list {
            @apply rtds-bg-white lg:rtds-bg-transparent lg:rtds-grid lg:rtds-gap-x-8 xl:rtds-gap-x-10 lg:rtds-grid-cols-3 xl:rtds-grid-cols-4 lg:rtds-p-4;
        }
    
        .has-megamenu .rtds-dropdown-menu__link {
            @apply rtds-p-4 lg:rtds-bg-transparent rtds-content-02 rtds-text-base xl:rtds-text-lg;
        }
    
        .rtds-dropdown-menu__megamenu.is-hidden {
            @apply rtds-invisible rtds-absolute lg:rtds-hidden lg:rtds-static rtds-overflow-hidden;
        }
    
        /* MEGAMENU MOBILE */
        .rtds-dropdown-menu.has-megamenu {
            @apply rtds-z-20 rtds-bg-white lg:rtds-static lg:rtds-z-auto lg:rtds-top-auto lg:rtds-left-auto lg:rtds-right-auto lg:rtds-bottom-auto;
        }
    
        .rtds-dropdown-menu.has-megamenu.has-dropdown-open {
            @apply rtds-top-0 rtds-left-0 rtds-right-0 rtds-bottom-0 rtds-absolute rtds-z-30 lg:rtds-static lg:rtds-top-auto lg:rtds-left-auto lg:rtds-right-auto lg:rtds-bottom-auto;
        }
    
        .rtds-dropdown-menu__megamenu .rtds-dropdown-menu__list {
            @apply rtds-invisible rtds-transition-all rtds-opacity-0 rtds-translate-x-full lg:rtds-translate-x-0 rtds-relative rtds-left-full rtds-right-0 rtds-w-0 rtds-h-0 lg:rtds-h-auto lg:rtds-w-full lg:rtds-left-auto lg:rtds-right-auto;
        }
    
        .rtds-dropdown-menu__megamenu.is-open .rtds-dropdown-menu__list {
            @apply rtds-visible rtds-opacity-100 rtds-translate-x-0 rtds-left-0 rtds-w-full;
        }
        
        /* MANAGING NAV PANEL DROPDOWN OPEN */
        :where(.rtds-primary-navigation.has-megamenu) .has-inner-dropdown-open {
            @apply rtds-absolute rtds-top-0 rtds-left-0 rtds-right-0 rtds-bottom-0 rtds-z-30 rtds-bg-white xl:rtds-bg-transparent xl:rtds-z-auto xl:rtds-top-auto xl:rtds-left-auto xl:rtds-right-auto xl:rtds-bottom-auto xl:rtds-static;
        }
    }
  • URL: /components/raw/dropdown-menu/dropdown-menu.css
  • Filesystem Path: components/03-molecules/dropdown-menu/dropdown-menu.css
  • Size: 4.1 KB
  • Content:
    /*
     *   This content is licensed according to the W3C Software License at
     *   https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
     *
     *   Supplemental JS for the disclosure menu keyboard behavior
     */
    
    'use strict';
    
    // Helper function to find the closest ancestor with a specific tag name
    function findAncestor(element, tagName) {
      while (element) {
        if (element.tagName.toLowerCase() === tagName) {
          return element;
        }
        element = element.parentElement;
      }
      return null;
    }
    
    class DisclosureNav {
      constructor(domNode) {
        this.rootNode = domNode;
        this.controlledNodes = [];
        this.openIndex = null;
        this.useArrowKeys = true;
        this.topLevelNodes = [
          ...this.rootNode.querySelectorAll(
            '.main-link, .rtds-dropdown-trigger'
          ),
        ];
    
        this.topLevelNodes.forEach((node) => {
          if (
            node.tagName.toLowerCase() === 'button' &&
            node.hasAttribute('aria-controls')
          ) {
            // Supporta sia <ul> che <div>
            const menu = node.parentNode.querySelector('ul, div');
    
            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));
          }
        });
    
        // Aggiungiamo un event listener per il click globale
        document.addEventListener('click', this.onDocumentClick.bind(this));
        // Manteniamo anche l'evento focusout per la navigazione da tastiera
        this.rootNode.addEventListener('focusout', this.onBlur.bind(this));
      }
    
      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.toggleExpand(this.openIndex, false);
      }
    
      onBlur(event) {
        // Verifichiamo se il nuovo elemento focusato è all'interno del menu
        const menuContainsFocus = this.rootNode.contains(event.relatedTarget);
        
        // Se il focus è uscito dal menu e non è stato spostato su un altro elemento del menu
        if (!menuContainsFocus && this.openIndex !== null) {
          // Aggiungiamo un piccolo delay per permettere al focus di stabilizzarsi
          setTimeout(() => {
            if (!this.rootNode.contains(document.activeElement)) {
              this.toggleExpand(this.openIndex, false);
            }
          }, 0);
        }
      }
    
      onButtonClick(event) {
        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) {
        var targetButtonIndex = this.topLevelNodes.indexOf(document.activeElement);
    
        if (event.key === 'Escape') {
          this.toggleExpand(this.openIndex, false);
        } else if (
          this.useArrowKeys &&
          this.openIndex === targetButtonIndex &&
          event.key === 'ArrowDown'
        ) {
          event.preventDefault();
          this.controlledNodes[this.openIndex].querySelector('a').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) {
          return;
        }
    
        var menuLinks = Array.prototype.slice.call(
          this.controlledNodes[this.openIndex].querySelectorAll('a')
        );
        var currentIndex = menuLinks.indexOf(document.activeElement);
    
        if (event.key === 'Escape') {
          this.topLevelNodes[this.openIndex].focus();
          this.toggleExpand(this.openIndex, false);
        } else if (this.useArrowKeys) {
          this.controlFocusByKey(event, menuLinks, currentIndex);
        }
      }
    
      toggleExpand(index, expanded) {
        if (this.openIndex !== index) {
          this.toggleExpand(this.openIndex, false);
        }
    
        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) {
          // Trova l'elemento padre con la classe has-dropdown-menu
          const parentMenu = domNode.closest('.has-dropdown-menu');
          // Trova il modulo di navigazione principale
          const navModule = domNode.closest('.rtds-primary-navigation__module');
          
          // Verifica se è un mega menu
          const isMegaMenu = parentMenu && parentMenu.classList.contains('has-megamenu');
    
          // Gestione delle classi per mostrare/nascondere il menu
          if (show) {
            // Rimuove la classe appropriata in base al tipo di menu
            domNode.classList.remove(isMegaMenu ? 'is-hidden' : 'rtds-hidden');
            domNode.classList.add('is-open');
            if (parentMenu) {
              parentMenu.classList.add('has-dropdown-open');
            }
            if (navModule) {
              navModule.classList.add('has-inner-dropdown-open');
            }
          } else {
            domNode.classList.remove('is-open');
            // Aggiunge la classe appropriata in base al tipo di menu
            domNode.classList.add(isMegaMenu ? 'is-hidden' : 'rtds-hidden');
            if (parentMenu) {
              parentMenu.classList.remove('has-dropdown-open');
            }
            if (navModule) {
              navModule.classList.remove('has-inner-dropdown-open');
            }
          }
    
          const rect = domNode.getBoundingClientRect();
    
          const isOverflowingRight = rect.right > window.innerWidth;
          const isOverflowingLeft = rect.left < 0;
    
          domNode.classList.toggle('rtds-right-0', isOverflowingRight);
          domNode.classList.toggle('rtds-left-0', isOverflowingLeft);
        }
      }
    
      updateKeyControls(useArrowKeys) {
        this.useArrowKeys = useArrowKeys;
      }
    
      // Aggiungiamo un nuovo metodo per gestire i click globali
      onDocumentClick(event) {
        // Se il click è all'interno del menu, non facciamo nulla
        if (this.rootNode.contains(event.target)) {
          return;
        }
        
        // Se c'è un menu aperto, lo chiudiamo
        if (this.openIndex !== null) {
          this.toggleExpand(this.openIndex, false);
        }
      }
    }
    
    /* Inizializza i Disclosure Menus */
    
    window.addEventListener(
      'load',
      function () {
        // Seleziona sia gli elementi con la classe .has-dropdown-menu che i div con la classe .dropdown
        var menus = document.querySelectorAll('.has-dropdown-menu, div.rtds-dropdown-menu');
        var disclosureMenus = [];
    
        for (var i = 0; i < menus.length; i++) {
          disclosureMenus[i] = new DisclosureNav(menus[i]);
        }
      },
      false
    );
  • URL: /components/raw/dropdown-menu/dropdown-menu.js
  • Filesystem Path: components/03-molecules/dropdown-menu/dropdown-menu.js
  • Size: 7.9 KB

Dropdown Menu Component

Il componente Dropdown Menu fornisce un menu a discesa accessibile e interattivo, con supporto per navigazione da tastiera e screen reader. Supporta diverse varianti, inclusa una versione megamenu per contenuti più complessi e una variante actions per menu di azioni.

Note per lo Sviluppo

Il componente può essere utilizzato in due modalità:

  • Come componente dropdown indipendente (wrapper <div>)
  • Come elemento di lista in un menu (variante list-item, es. nel menu primario)

Nota importante: In preview, lo stile del componente potrebbe apparire incompleto poiché dipende dal contesto del menu/liste in cui viene utilizzato.

Markup Base

<div class="rtds-dropdown-menu">
    <button class="rtds-dropdown-menu__trigger rtds-dropdown-trigger rtds-group rtds-w-full rtds-flex rtds-items-center" aria-expanded="false" aria-controls="submenuId01">
        Menu item
        <!-- Icona trigger -->
        <svg class="rtds-ml-auto rtds-transition-all rtds-dropdown-menu__trigger-icon group-aria-expanded:-rtds-rotate-180">...</svg>
    </button>
    <ul class="rtds-dropdown-menu__list rtds-hidden rtds-border rtds-border-t-0" id="submenuId01">
        <li class="rtds-dropdown-menu__item rtds-group/menu-item">
            <a class="rtds-dropdown-menu__link rtds-block rtds-transition" href="">
                <div class="rtds-flex rtds-gap-2 rtds-items-center">
                    <!-- Icona sinistra (opzionale) -->
                    <span class="rtds-grow">Item label</span>
                    <!-- Icona destra (opzionale) -->
                </div>
                <!-- Descrizione (opzionale) -->
            </a>
        </li>
        <!-- Altri elementi del menu -->
    </ul>
</div>

Configurazione

Parametri Principali

  • id (string): ID univoco per il dropdown (necessario per l’accessibilità)
  • label (string): Testo del pulsante trigger
  • items (array): Lista degli elementi del menu
    • label (string): Testo dell’elemento
    • description (string): Descrizione opzionale dell’elemento
    • iconLeft (string): ID dell’icona da mostrare a sinistra
    • iconRight (string): ID dell’icona da mostrare a destra
  • listItem (boolean): Se true, il componente viene renderizzato come <li> invece di <div>
  • classes (string): Classi CSS aggiuntive per personalizzare l’aspetto
  • hasMegamenu (boolean): Se true, il dropdown ha un megamenu

In variante “actions”

  • context: per accessibilità - aggiunge eventuale contesto al dropdown, es nel caso di uso con una lista di cards e quindi con necessità di differenziare il nome accessibile del trigger dando contesto

Stili e Personalizzazione

  • triggerSpacing (string): Spaziatura del pulsante trigger
  • triggerFontSize (string): Dimensione del font del pulsante trigger
  • triggerTextColor (string): Colore del testo del trigger
  • triggerAriaExpandedStyles (string): Stili applicati quando il menu è espanso
  • listWidth (string): Larghezza del menu a discesa
  • listResponsiveStyles (string): Stili responsive per il menu
  • listItemLinkRadius (string): Bordi arrotondati per gli elementi del menu
  • listItemLinkFontSize (string): Dimensione del font per i link degli elementi
  • listPosition (string): Posizione del menu a discesa (gestisce il posizionamento a sinistra/destra)
  • hoverStyles (string): Stili per l’hover sugli elementi

Blocchi Disponibili

  • preContent: Utilizzato per elementi come avatar utente o icone aggiuntive
  • classes: Personalizzazione delle classi del componente
  • triggerIcon: Personalizzazione dell’icona del trigger
  • listStart: Personalizzazione dell’inizio della lista
  • listEnd: Personalizzazione della fine della lista

Varianti Supportate

  1. Default

    • Menu a discesa standard
    • Larghezza completa
    • Stili responsive con bordo e ombra su desktop
  2. List Item

    • Versione compatibile con liste
    • Larghezza fissa su desktop (52)
    • Stili responsive con bordo e ombra
  3. Megamenu

    • Menu a discesa a larghezza piena
    • Stili speciali per il trigger quando espanso
    • Layout a container su desktop
    • Icone diverse per mobile e desktop
  4. Actions

    • Menu di azioni compatto con icona ellipsis verticale
    • Posizionamento a destra con larghezza fissa (25ch)
    • Stili simili al menu delle azioni delle card
    • Ideale per menu contestuali in componenti come card, tabelle, ecc.
    • Trigger con stile button invertito e stato attivo
    • Elementi del menu con icone a sinistra e stili hover/focus

Comportamento

Interattività

  • Apertura/chiusura al click sul trigger
  • Chiusura automatica quando il focus si sposta fuori dal menu
  • Transizioni fluide per apertura/chiusura
  • Gestione intelligente del posizionamento per evitare overflow

Accessibilità

  • Implementazione WAI-ARIA per menu a discesa
  • Supporto completo per navigazione da tastiera
  • Gestione appropriata degli attributi aria-expanded e aria-controls
  • Focus management per una navigazione efficiente
  • Freccia su/giù: Navigazione tra gli elementi del menu
  • Freccia sinistra/destra: Navigazione tra i trigger del menu
  • Home/End: Vai al primo/ultimo elemento
  • Escape: Chiude il menu e riporta il focus al trigger
  • Tab: Navigazione standard tra elementi focusabili

Classi CSS Principali

  • rtds-dropdown-menu: Classe base del componente
  • rtds-dropdown-menu__trigger: Pulsante trigger
  • rtds-dropdown-menu__list: Lista degli elementi del menu
  • rtds-dropdown-menu__item: Elemento del menu
  • rtds-dropdown-menu__link: Link dell’elemento
  • rtds-dropdown-menu__megamenu: Contenitore per la variante megamenu
  • has-dropdown-menu: Classe per elementi che contengono un dropdown
  • has-dropdown-open: Classe per elementi con dropdown aperto
  • is-open: Classe per menu aperti
  • is-hidden: Classe per menu nascosti (megamenu)
  • is-dropdown-menu--actions: Classe specifica per la variante actions

JavaScript

Il componente include una gestione avanzata della navigazione da tastiera e dell’accessibilità:

  • Classe DisclosureNav per gestire il comportamento del menu
  • Rilevamento automatico dei menu nella pagina
  • Gestione intelligente del focus e della navigazione
  • Supporto per menu annidati e megamenu
  • Gestione dell’overflow per evitare che il menu esca dallo schermo

Funzionalità Principali

  • Apertura/chiusura al click
  • Navigazione con frecce direzionali
  • Gestione del focus quando il menu si chiude
  • Rilevamento automatico dell’overflow
  • Supporto per diversi tipi di menu (standard, lista, megamenu, actions)