<nav class="rtds-user-dropdown" aria-label="Utente" id="userDropdown">

    <div class="rtds-dropdown-menu rtds-user-dropdown__menu has-dropdown-menu rtds-flex-1">
        <button class="rtds-dropdown-menu__trigger rtds-dropdown-trigger rtds-group hover:rtds-underline hover:rtds-content-primary aria-expanded:rtds-bg-white aria-expanded:rtds-content-primary aria-expanded:rtds-relative" aria-expanded="false" aria-controls="userDropdown">
            Mario Rossi<svg class="rtds-icon rtds-fill-current rtds-w-5 rtds-h-5 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>

        <ul class="rtds-dropdown-menu__list rtds-user-dropdown__menu-list rtds-hidden rtds-border rtds-w-full lg:rtds-rounded lg:rtds-shadow-md lg:rtds-absolute" id="userDropdown">

            <li class="rtds-dropdown-menu__item rtds-user-dropdown__menu-item">
                <div class="rtds-user-dropdown__menu-label rtds-items-center">
                    Item label 1
                </div>
                <ul class="rtds-user-dropdown__menu-sublist">

                    <li class="rtds-user-dropdown__menu-label">
                        <a class="rtds-user-dropdown__menu-link" href="">
                            Item label 1
                        </a>
                    </li>

                    <li class="rtds-user-dropdown__menu-label">
                        <a class="rtds-user-dropdown__menu-link" href="">
                            Item label 1
                        </a>
                    </li>

                </ul>
            </li>

            <li class="rtds-dropdown-menu__item rtds-user-dropdown__menu-item">
                <div class="rtds-user-dropdown__menu-label rtds-items-center">
                    Item label 1
                </div>
                <ul class="rtds-user-dropdown__menu-sublist">

                    <li class="rtds-user-dropdown__menu-label">
                        <a class="rtds-user-dropdown__menu-link" href="">
                            Item label 1
                        </a>
                    </li>

                    <li class="rtds-user-dropdown__menu-label">
                        <a class="rtds-user-dropdown__menu-link" href="">
                            Item label 1
                        </a>
                    </li>

                </ul>
            </li>

            <li class="rtds-dropdown-menu__item rtds-user-dropdown__menu-item">
                <a class="rtds-user-dropdown__menu-logout rtds-user-dropdown__menu-link is-logout" href="#">
                    Esci<svg class="rtds-icon rtds-fill-current rtds-w-5 rtds-h-5 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#solid--arrow-right-start-on-rectangle" />
                    </svg>
                </a>
            </li>

        </ul>

    </div>
</nav>
{% if isUserLoggedIn %}
<nav class="rtds-user-dropdown{% if classes %} {{ classes }}{% endif %}" aria-label="Utente" id="userDropdown">

    <div class="rtds-dropdown-menu rtds-user-dropdown__menu has-dropdown-menu rtds-flex-1">
        <button class="rtds-dropdown-menu__trigger rtds-dropdown-trigger rtds-group{% if triggerLabelColor %} {{ triggerLabelColor }}{% endif %} hover:rtds-underline hover:rtds-content-primary aria-expanded:rtds-bg-white aria-expanded:rtds-content-primary aria-expanded:rtds-relative" aria-expanded="false" aria-controls="{{ userDropdownId }}">
            {% block triggerLabel %}{{ userName | default('Username Surname') }}{% endblock %}
            {%- render '@icon--small', {id: 'mini--chevron-down', size: 'rtds-w-5 rtds-h-5', classes: 'rtds-ml-auto rtds-transition-all rtds-dropdown-menu__trigger-icon group-aria-expanded:-rtds-rotate-180'}, true -%}
        </button>

        <ul class="rtds-dropdown-menu__list rtds-user-dropdown__menu-list rtds-hidden rtds-border rtds-w-full lg:rtds-rounded lg:rtds-shadow-md lg:rtds-absolute{% if listClasses %} {{ listClasses }}{% endif %}" id="{{ userDropdownId }}">
            {% for i in range(1, 3) %}
            <li class="rtds-dropdown-menu__item rtds-user-dropdown__menu-item">
                <div class="rtds-user-dropdown__menu-label rtds-items-center">
                    Item label 1
                </div>
                <ul class="rtds-user-dropdown__menu-sublist">
                    {% for i in range(1, 3) %}
                    <li class="rtds-user-dropdown__menu-label">
                        <a class="rtds-user-dropdown__menu-link" href="">
                            Item label 1
                        </a>
                    </li>
                    {% endfor %}
                </ul>
            </li>
            {% endfor %}

            <li class="rtds-dropdown-menu__item rtds-user-dropdown__menu-item">
                <a class="rtds-user-dropdown__menu-logout rtds-user-dropdown__menu-link is-logout" href="#">
                    Esci
                    {%- render '@icon--small', {id: 'solid--arrow-right-start-on-rectangle', size: 'rtds-w-5 rtds-h-5', classes: 'rtds-ml-auto rtds-transition-all rtds-dropdown-menu__trigger-icon group-aria-expanded:-rtds-rotate-180'}, true -%}
                </a>
            </li>

        </ul>

    </div>
</nav>
{% else %}
{% block loginElement %}{%- render '@button--icon-right', {label: loginLabel if loginLabel else 'Login', href: loginHref if loginHref else '#', icon: 'outline--arrow-right-start-on-rectangle', classes: 'rtds-btn--outlined'}, true -%}{% endblock %}
{% endif %}
{
  "userDropdownId": "userDropdown",
  "userName": "Mario Rossi",
  "loginHref": "#",
  "loginLabel": "Login",
  "isUserLoggedIn": true
}
  • Content:
    .rtds-user-dropdown {
        display: flex;
    }
    @media (min-width: 1024px) {
        .rtds-user-dropdown__menu.has-dropdown-menu {
            position: relative;
        }
    }
    :where(.rtds-user-dropdown__menu) .rtds-dropdown-trigger {
        width: 100%;
        padding: var(--spacing-3);
        font-size: var(--fontsize-text-sm);
        font-weight: 500;
        display: flex;
        align-items: center;
        gap: var(--spacing-2);
        transition-property: all;
        transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
        transition-duration: 150ms;
    }
    :where(.rtds-user-dropdown__menu) .rtds-dropdown-trigger:hover {
        --tw-bg-opacity: 1;
        background-color: rgb(255 255 255 / var(--tw-bg-opacity, 1));
        text-decoration-line: underline;
            color: var(--color-content-primary);
    }
    @media (min-width: 1024px) {
        :where(.rtds-user-dropdown__menu) .rtds-dropdown-trigger {
            border-radius: 0.25rem;
            font-size: var(--fontsize-text-base);
        }
    }
    .rtds-user-dropdown__menu-label {
        --tw-bg-opacity: 1;
        background-color: rgb(255 255 255 / var(--tw-bg-opacity, 1));
        padding: var(--spacing-3);
    }
    .rtds-user-dropdown__menu-list {
        z-index: 20;
        font-size: var(--fontsize-text-base);
    }
    @media (min-width: 1024px) {
        .rtds-user-dropdown__menu-list {
            font-size: var(--fontsize-text-sm);
        }
    }
    .rtds-user-dropdown__menu-sublist {
        --tw-bg-opacity: 1;
        background-color: rgb(255 255 255 / var(--tw-bg-opacity, 1));
        padding-left: var(--spacing-3);
    }
    .rtds-user-dropdown__menu-link:hover {
        text-decoration-line: underline;
            color: var(--color-content-primary);
    }
    .rtds-user-dropdown__menu-logout {
        justify-content: space-between;
        --tw-bg-opacity: 1;
        background-color: rgb(255 255 255 / var(--tw-bg-opacity, 1));
        padding: var(--spacing-3);
        display: flex;
        align-items: center;
        gap: var(--spacing-2);
    }
    .rtds-user-dropdown__login-trigger {
        padding: var(--spacing-3);
        font-size: var(--fontsize-text-sm);
        font-weight: 500;
        display: flex;
        align-items: center;
        gap: var(--spacing-2);
        transition-property: all;
        transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
        transition-duration: 150ms;
    }
    .rtds-user-dropdown__login-trigger:hover {
        --tw-bg-opacity: 1;
        background-color: rgb(255 255 255 / var(--tw-bg-opacity, 1));
        text-decoration-line: underline;
            color: var(--color-content-primary);
    }
    @media (min-width: 1024px) {
        .rtds-user-dropdown__login-trigger {
            border-radius: 0.25rem;
            font-size: var(--fontsize-text-base);
        }
    }
    
  • URL: /components/raw/user-dropdown/user-dropdown.built.css
  • Filesystem Path: components/03-molecules/user-dropdown/user-dropdown.built.css
  • Size: 2.6 KB
  • Content:
    @layer components {
        .rtds-user-dropdown {
            @apply rtds-flex;
        }
    
        .rtds-user-dropdown__menu.has-dropdown-menu {
            @apply lg:rtds-relative;
        }
    
        :where(.rtds-user-dropdown__menu) .rtds-dropdown-trigger {
            @apply rtds-transition-all rtds-w-full rtds-flex rtds-p-3 rtds-gap-2 rtds-text-sm lg:rtds-text-base rtds-items-center rtds-font-medium hover:rtds-underline hover:rtds-content-primary hover:rtds-bg-white lg:rtds-rounded;
        }
    
        .rtds-user-dropdown__menu-label {
            @apply rtds-p-3 rtds-bg-white;
        }
    
        .rtds-user-dropdown__menu-list {
            @apply rtds-z-20 rtds-text-base lg:rtds-text-sm;
        }
    
        .rtds-user-dropdown__menu-sublist {
            @apply rtds-pl-3 rtds-bg-white;
        }
    
        .rtds-user-dropdown__menu-link {
            @apply hover:rtds-underline hover:rtds-content-primary;
        }
    
        .rtds-user-dropdown__menu-logout {
            @apply rtds-flex rtds-items-center rtds-justify-between rtds-gap-2 rtds-p-3 rtds-bg-white;
        }
    
        .rtds-user-dropdown__login-trigger {
            @apply rtds-transition-all rtds-flex rtds-p-3 rtds-gap-2 rtds-text-sm lg:rtds-text-base rtds-items-center rtds-font-medium hover:rtds-underline hover:rtds-content-primary hover:rtds-bg-white lg:rtds-rounded;
        }
    }
  • URL: /components/raw/user-dropdown/user-dropdown.css
  • Filesystem Path: components/03-molecules/user-dropdown/user-dropdown.css
  • Size: 1.3 KB

User Dropdown

Componente per il menu utente nell’header dei servizi. Gestisce due stati: utente non autenticato (ghost link “Accedi”) e utente autenticato (trigger dropdown con nome).


Comportamento

Il componente si renderizza diversamente in base a isUserLoggedIn:

  • isUserLoggedIn: false (default) — bottone outlined “Login” con icona outline--arrow-right-start-on-rectangle. Impostare loginHref per la navigazione alla pagina di login.
  • isUserLoggedIn: true<nav aria-label="Utente"> con trigger <button> che mostra il nome utente e chevron-down (senza icona utente); apre un dropdown con voci di navigazione e link “Esci”.

Varianti

Variante Descrizione
Non loggato (default) Bottone outlined Login con icona arrow-right-start-on-rectangle
Utente loggato Trigger dropdown Nome Cognome [ chevron ] — senza icona utente

Parametri di configurazione

Contesto di sviluppo Fractal/Nunjucks — Questa sezione riguarda esclusivamente i parametri del context .config.yml. Per l’uso nei temi o CMS fare riferimento alla sezione Esempi di utilizzo.

Parametri Base

Parametro Tipo Obbligatorio Descrizione
isUserLoggedIn booleano No Se true renderizza il menu dropdown autenticato; altrimenti il ghost link. Default: false
userName stringa No Nome visualizzato nel trigger loggato. Default: "Username Surname"
loginHref stringa No Href del ghost link “Accedi”. Default: "#"
loginLabel stringa No Testo del bottone “Login”. Default: "Login"
userDropdownId stringa No ID della <ul> dropdown e target di aria-controls. Default: "userDropdown"
triggerLabelColor stringa No Classe CSS aggiuntiva per il colore del testo nel trigger loggato
classes stringa No Classi CSS aggiuntive sulla radice (<nav> se loggato, <a> se non loggato)
listClasses stringa No Classi CSS aggiuntive sulla <ul> dropdown (solo stato loggato)

Accessibilità

WCAG 2.1

Livello AA — criteri pertinenti:

  • 1.3.1 Informazioni e correlazioni — lo stato autenticato usa <nav aria-label="Utente"> come landmark di navigazione
  • 4.1.2 Nome, ruolo, valore — aria-expanded e aria-controls sul trigger comunicano stato e target del dropdown

Struttura e semantica

  • Non loggato<a> con testo visibile “Accedi”; l’icona è decorativa (aria-hidden gestito da @icon--small)
  • Loggato<nav aria-label="Utente"> landmark; trigger <button> con aria-expanded / aria-controls; lista <ul> con <li> e <a>

Attributi ARIA

Attributo Valori Condizione
aria-label "Utente" sempre sul <nav> (stato loggato)
aria-expanded "true" / "false" sul trigger <button> (stato loggato)
aria-controls ID della <ul> sul trigger <button> (stato loggato)
Tasto Azione
Tab / Shift+Tab Sposta il focus tra trigger e voci del menu
Enter / Space Apre o chiude il dropdown (stato loggato)
Escape Chiude il dropdown e riporta il focus al trigger

Gestione del focus

  • Focus visibile: lo stile :focus-visible è sempre visibile e non viene rimosso via CSS

Screen reader

  • La regione è annunciata come “Utente” (navigazione) — solo stato loggato
  • Il trigger viene annunciato con il nome utente e lo stato del menu (espanso / compresso)

Stili CSS

Classi BEM

Classe Elemento Descrizione
.rtds-user-dropdown radice <nav> contenitore stato loggato
.rtds-user-dropdown__menu <div> interno wrapper dropdown menu
.rtds-user-dropdown__menu-list <ul> lista voci dropdown
.rtds-user-dropdown__menu-item <li> voce del menu
.rtds-user-dropdown__menu-label <div> o <li> etichetta gruppo o voce
.rtds-user-dropdown__menu-sublist <ul> annidato sotto-lista voci
.rtds-user-dropdown__menu-link <a> link voce del menu
.rtds-user-dropdown__menu-logout <a> link “Esci”
.rtds-user-dropdown__login-trigger <a> ghost link stato non loggato

Esempi di utilizzo

<!-- Stato non autenticato -->
<a href="/login" class="rtds-btn rtds-btn--icon-right rtds-btn--outlined">
  Login
  <!-- icona outline--arrow-right-start-on-rectangle (iniettata da @button--icon-right) -->
</a>

<!-- Stato autenticato -->
<nav aria-label="Utente" class="rtds-user-dropdown">
  <div class="rtds-dropdown-menu rtds-user-dropdown__menu has-dropdown-menu">
    <button class="rtds-dropdown-menu__trigger rtds-dropdown-trigger"
            aria-expanded="false"
            aria-controls="user-menu">
      Mario Rossi
      <!-- icona mini--chevron-down -->
    </button>
    <ul id="user-menu" class="rtds-dropdown-menu__list rtds-user-dropdown__menu-list rtds-hidden">
      <li class="rtds-user-dropdown__menu-item">...</li>
      <li class="rtds-user-dropdown__menu-item">
        <a class="rtds-user-dropdown__menu-logout rtds-user-dropdown__menu-link" href="/logout">
          Esci
        </a>
      </li>
    </ul>
  </div>
</nav>

Blocchi Nunjucks

Il componente espone due blocchi sovrascrivibili da template child tramite extends '@user-dropdown' (Nunjucks template inheritance).

Blocco Posizione Contenuto default Note
triggerLabel Dentro <button>, prima del chevron Testo userName (default: “Username Surname”) Il chevron mini--chevron-down è fuori dal blocco e rimane sempre presente
loginElement Ramo non-loggato render '@button--icon-right' outlined Sostituisce l’intero elemento non-loggato

Un child template estende @user-dropdown e sovrascrive solo i blocchi di cui ha bisogno — il resto della struttura (nav, ul, voci, logout) è ereditato automaticamente. Vedere @user-dropdown-servizi come esempio di implementazione.


Note

  • Dipende da @dropdown-menu per la gestione JS del menu a tendina (stato loggato)
  • Usato da @top-bar e @primary-navigation nel portale istituzionale (core)
  • Per i template-servizi usare @user-dropdown-servizi (ghost link con icona), che estende questo componente via Nunjucks extends
  • Il parametro classes si applica solo in stato loggato (radice <nav>); non viene inoltrato al bottone outlined in stato non loggato