<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
}
.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);
}
}
@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;
}
}
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).
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”.| 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 |
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.
| 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) |
Livello AA — criteri pertinenti:
<nav aria-label="Utente"> come landmark di navigazionearia-expanded e aria-controls sul trigger comunicano stato e target del dropdown<a> con testo visibile “Accedi”; l’icona è decorativa (aria-hidden gestito da @icon--small)<nav aria-label="Utente"> landmark; trigger <button> con aria-expanded / aria-controls; lista <ul> con <li> e <a>| 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 |
:focus-visible è sempre visibile e non viene rimosso via CSSespanso / compresso)| 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 |
<!-- 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>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.
@dropdown-menu per la gestione JS del menu a tendina (stato loggato)@top-bar e @primary-navigation nel portale istituzionale (core)@user-dropdown-servizi (ghost link con icona), che estende questo componente via Nunjucks extendsclasses si applica solo in stato loggato (radice <nav>); non viene inoltrato al bottone outlined in stato non loggato