<nav class="rtds-primary-navigation
rtds-primary-navigation--megamenu has-megamenu
" aria-label="Principale" id="siteNavWrapper">
<button type="button" class="rtds-btn rtds-btn--only-text rtds-rounded-0 lg:rtds-hidden rtds-ml-auto rtds-btn--icon rtds-group" aria-expanded="false" aria-controls="mainNavPanel" aria-haspopup="dialog" id="mobileNavToggle">
<svg class="rtds-icon rtds-fill-current rtds-w-6 rtds-h-6 rtds-m-0 rtds-p-0
rtds-transition-all rtds-duration-200 rtds-ease-out rtds-transform
group-hover:rtds-translate-none is-show-menu
group-aria-expanded:rtds-hidden" aria-hidden="true" focusable="false" role="img">
<use href="../../icons.svg#mini--bars-3" />
</svg>
<svg class="rtds-icon rtds-fill-current rtds-w-6 rtds-h-6 rtds-m-0 rtds-p-0 rtds-transition-all
rtds-duration-200 rtds-ease-out rtds-transform
group-hover:rtds-translate-none is-close-menu rtds-hidden
group-aria-expanded:rtds-inline-block" aria-hidden="true" focusable="false" role="img">
<use href="../../icons.svg#mini--x-mark" />
</svg>
<span class="rtds-sr-only is-show-menu">
Menu
</span>
</button>
<!-- Mobile panel -->
<div class="rtds-primary-navigation__panel" id="mainNavPanel" role="dialog" aria-modal="true" aria-label="Menu di navigazione">
<!-- Main nav -->
<div class="rtds-primary-navigation__module is-main lg:rtds-border-b-0">
<ul class="rtds-primary-navigation__list ">
<li class="rtds-primary-navigation__item">
<a href="" class="rtds-primary-navigation__first-level rtds-primary-navigation__link rtds-group rtds-text-base xl:rtds-text-lg">
Temi e servizi
</a>
</li>
<li class="rtds-primary-navigation__item">
<a href="" class="rtds-primary-navigation__first-level rtds-primary-navigation__link rtds-group rtds-text-base xl:rtds-text-lg">
Bandi e opportunità
</a>
</li>
<li class="rtds-primary-navigation__item">
<a href="" class="rtds-primary-navigation__first-level rtds-primary-navigation__link rtds-group rtds-text-base xl:rtds-text-lg">
Regione
</a>
</li>
<li class="rtds-dropdown-menu has-dropdown-menu rtds-primary-navigation__item 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-base xl:rtds-text-lg rtds-primary-navigation__first-level rtds-primary-navigation__link" aria-expanded="false" aria-controls="submenumenu-01">
Dropdown 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="submenumenu-01">
<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 rtds-text-base xl:rtds-text-lg" 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 rtds-text-base xl:rtds-text-lg" 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 rtds-text-base xl:rtds-text-lg" 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 rtds-text-base xl:rtds-text-lg" 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 rtds-text-base xl:rtds-text-lg" 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 rtds-text-base xl:rtds-text-lg" 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 rtds-text-base xl:rtds-text-lg" 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 rtds-text-base xl:rtds-text-lg" 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 rtds-text-base xl:rtds-text-lg" 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 rtds-text-base xl:rtds-text-lg" href="">
<div class="rtds-flex rtds-gap-2 rtds-items-center">
<span class="rtds-grow">List item</span>
</div>
</a>
</li>
</ul>
</div>
</li>
</ul>
</div>
</div>
<div class="rtds-primary-navigation__backdrop rtds-bg-black/25 rtds-top-[--header-height] lg:rtds-hidden"></div>
</nav>
{% extends '@primary-navigation' %}
{% block classes %}
{{ super() }} rtds-primary-navigation--megamenu has-megamenu
{% endblock classes %}
{% block dropdown %}
{% render '@dropdown-menu--megamenu', { listItem: true, label: firstLevel.label,id: 'submenumenu-01', classes: 'rtds-primary-navigation__item', listPosition: dropdownListPosition, listClasses: itemClasses, listWidth: dropdownListWidth, triggerTextColor: itemTriggerTextColor, triggerFontSize:itemFontSize, listItemLinkFontSize: itemDropdownFontSize, items: dropdownItems, triggerClasses: itemTriggerClasses }, true %}
{% endblock dropdown %}
{
"navId": "mainNavPanel",
"itemTriggerClasses": "rtds-primary-navigation__first-level rtds-primary-navigation__link",
"itemFontSize": "rtds-text-base xl:rtds-text-lg",
"itemDropdownFontSize": "rtds-text-base xl:rtds-text-lg",
"firstLevels": [
{
"label": "Temi e servizi"
},
{
"label": "Bandi e opportunità"
},
{
"label": "Regione"
},
{
"label": "Dropdown item",
"hasSubItems": true
}
],
"dropdownItems": [
{
"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"
}
]
}
/**
* PRIMARY NAVIGATION
*
*/
.rtds-primary-navigation {
display: flex;
}
@media (min-width: 1024px) {
.rtds-primary-navigation__item {
display: flex;
align-items: center;
}
.rtds-primary-navigation__item:where(.has-dropdown-menu) {
position: relative;
}
}
.rtds-primary-navigation__first-level {
font-weight: 700;
}
.rtds-primary-navigation__panel {
visibility: hidden;
position: fixed;
top: var(--header-height);
bottom: var(--spacing-0);
left: 12%;
width: 88%;
--tw-translate-x: 100%;
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
flex-direction: column;
overflow-y: auto;
border-left-width: 1px;
--tw-bg-opacity: 1;
background-color: rgb(255 255 255 / var(--tw-bg-opacity, 1));
border-color: var(--color-border-primary);
transition-property: all;
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
transition-duration: 150ms;
}
@media (min-width: 1024px) {
.rtds-primary-navigation__panel {
visibility: visible;
position: static;
left: var(--spacing-0);
width: auto;
transform: none;
overflow: visible;
border-left-width: 0px;
background-color: transparent;
}
}
.rtds-primary-navigation__panel.is-open {
visibility: visible;
left: 12%;
z-index: 20;
--tw-translate-x: var(--spacing-0);
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
--tw-bg-opacity: 1;
background-color: rgb(255 255 255 / var(--tw-bg-opacity, 1));
display: flex;
}
body.rtds-overflow-hidden .rtds-primary-navigation__backdrop,
:root.rtds-overflow-hidden .rtds-primary-navigation__backdrop {
position: fixed;
right: var(--spacing-0);
bottom: var(--spacing-0);
left: var(--spacing-0);
z-index: 10;
}
@media (min-width: 1024px) {
body.rtds-overflow-hidden .rtds-primary-navigation__backdrop,
:root.rtds-overflow-hidden .rtds-primary-navigation__backdrop {
display: none;
}
}
.rtds-primary-navigation__list {
display: grid;
gap: var(--spacing-2);
}
@media (min-width: 1024px) {
.rtds-primary-navigation__list {
display: flex;
justify-content: flex-end;
gap: var(--spacing-4);
}
}
@media (min-width: 1280px) {
.rtds-primary-navigation__list {
gap: var(--spacing-8);
}
}
.rtds-primary-navigation__link.is-current,
.rtds-primary-navigation__link:hover {
position: relative;
color: var(--color-content-primary);
}
.rtds-primary-navigation__link.is-current::after,
.rtds-primary-navigation__link:hover::after {
position: absolute;
left: var(--spacing-0);
bottom: var(--spacing-0);
display: block;
height: 1px;
width: 100%;
border-top-width: 2px;
border-color: currentColor;
content: var(--tw-content);
background-color: transparent;
}
.rtds-primary-navigation__link {
min-height: var(--spacing-14);
width: 100%;
padding: var(--spacing-3);
display: flex;
align-items: center;
gap: var(--spacing-2);
line-height: 1.25;
}
.rtds-primary-navigation__link:hover {
text-decoration-line: none;
color: var(--color-content-primary);
}
@media (min-width: 1024px) {
.rtds-primary-navigation__link {
height: 100%;
justify-content: center;
text-align: center;
}
}
/* MOBILE MENU */
.rtds-primary-navigation__module {
align-items: flex-start;
border-bottom-width: 1px;
padding: var(--spacing-2);
border-color: var(--color-border-gray-01);
display: grid;
}
.rtds-primary-navigation__module:last-child {
border-bottom-width: 0px;
}
@media (min-width: 1024px) {
.rtds-primary-navigation__module {
display: block;
flex: 1 1 0%;
padding: var(--spacing-0);
}
}
/* MEGAMENU container fix */
@media (min-width: 1024px) {
.rtds-primary-navigation .rtds-dropdown-menu__megamenu.is-open {
display: flex;
justify-content: center;
}
.rtds-primary-navigation .rtds-dropdown-menu__list {
flex: 1 1 0%;
}
}
/**
* PRIMARY NAVIGATION
*
*/
@layer components {
.rtds-primary-navigation {
@apply rtds-flex;
}
.rtds-primary-navigation__item {
@apply lg:rtds-flex lg:rtds-items-center;
}
.rtds-primary-navigation__item:where(.has-dropdown-menu) {
@apply lg:rtds-relative;
}
.rtds-primary-navigation__first-level {
@apply rtds-font-bold;
}
.rtds-primary-navigation__panel {
@apply rtds-flex-col rtds-bg-white rtds-transition-all rtds-invisible rtds-w-[88%] lg:rtds-bg-transparent lg:rtds-w-auto rtds-fixed lg:rtds-static lg:rtds-visible rtds-top-[--header-height] rtds-bottom-0 rtds-left-[12%] lg:rtds-left-0 rtds-border-l rtds-border-primary lg:rtds-border-l-0 rtds-overflow-y-auto lg:rtds-overflow-visible rtds-translate-x-full lg:rtds-transform-none;
}
.rtds-primary-navigation__panel.is-open {
@apply rtds-bg-white rtds-translate-x-0 rtds-visible rtds-flex rtds-z-20 rtds-left-[12%];
}
body.rtds-overflow-hidden .rtds-primary-navigation__backdrop,
:root.rtds-overflow-hidden .rtds-primary-navigation__backdrop {
@apply rtds-fixed rtds-right-0 rtds-bottom-0 rtds-left-0 lg:rtds-hidden rtds-z-10;
}
.rtds-primary-navigation__list {
@apply rtds-grid lg:rtds-flex lg:rtds-justify-end rtds-gap-2 lg:rtds-gap-4 xl:rtds-gap-8;
}
.rtds-primary-navigation__link.is-current,
.rtds-primary-navigation__link:hover {
@apply rtds-content-primary rtds-relative 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;
}
.rtds-primary-navigation__link {
@apply rtds-min-h-14 rtds-w-full lg:rtds-h-full rtds-flex rtds-items-center lg:rtds-justify-center lg:rtds-text-center rtds-leading-tight rtds-p-3 rtds-gap-2 hover:rtds-no-underline hover:rtds-content-primary;
}
/* MOBILE MENU */
.rtds-primary-navigation__module {
@apply rtds-p-2 lg:rtds-p-0 rtds-grid rtds-items-start lg:rtds-block lg:rtds-flex-1 rtds-border-b rtds-border-gray-01 last:rtds-border-b-0;
}
/* MEGAMENU container fix */
.rtds-primary-navigation .rtds-dropdown-menu__megamenu.is-open {
@apply lg:rtds-flex lg:rtds-justify-center;
}
.rtds-primary-navigation .rtds-dropdown-menu__list {
@apply lg:rtds-flex-1;
}
}
(function () {
'use strict';
var FOCUSABLE = 'a[href], button:not([disabled]), [tabindex]:not([tabindex="-1"])';
function getFocusable(panel) {
return Array.from(panel.querySelectorAll(FOCUSABLE));
}
function onKeydown(panel, e) {
if (e.key !== 'Tab') return;
var focusable = getFocusable(panel);
if (!focusable.length) return;
var first = focusable[0];
var last = focusable[focusable.length - 1];
if (e.shiftKey) {
if (document.activeElement === first) {
e.preventDefault();
last.focus();
}
} else {
if (document.activeElement === last) {
e.preventDefault();
first.focus();
}
}
}
function activateTrap(panel) {
var focusable = getFocusable(panel);
if (focusable.length) {
focusable[0].focus();
}
panel._trapHandler = onKeydown.bind(null, panel);
panel.addEventListener('keydown', panel._trapHandler);
}
function deactivateTrap(panel) {
if (panel._trapHandler) {
panel.removeEventListener('keydown', panel._trapHandler);
delete panel._trapHandler;
}
}
function init() {
var panel = document.getElementById('mainNavPanel');
if (!panel) return;
var observer = new MutationObserver(function (mutations) {
mutations.forEach(function (mutation) {
if (mutation.attributeName !== 'class') return;
if (panel.classList.contains('is-open')) {
activateTrap(panel);
} else {
deactivateTrap(panel);
}
});
});
observer.observe(panel, { attributes: true, attributeFilter: ['class'] });
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
})();
Il componente Primary Navigation gestisce la navigazione principale di un sito web. Include funzionalità di dropdown e supporta una versione mobile responsive.
Il componente è sempre renderizzato come <nav aria-label="Principale">. Contiene:
<button> — toggle per il pannello mobile, con aria-expanded e aria-controls<div id="mainNavPanel"> — pannello di navigazione (visibilità controllata via JS)<ul> con <li> e <a> per le voci di navigazione; le voci correnti hanno aria-current="page"Le voci con sottomenu includono un <button> con aria-expanded/aria-controls per gestire l’apertura del dropdown.
primary-navigation--megamenu: Versione con menu a tendina espanso (megamenu)Contesto di sviluppo Fractal/Nunjucks — Questa sezione riguarda esclusivamente i parametri del context
.config.ymlusati durante lo sviluppo nella libreria. Non descrive attributi HTML o proprietà da usare nei temi, CMS o ambienti di implementazione: per quello, fare riferimento alla sezione Esempi di utilizzo.
classes (stringa, opzionale): Classi CSS aggiuntive per il componentenavPanelClasses (stringa, opzionale): Classi per il pannello di navigazione mobilelistHorizontalAlignment (stringa, opzionale): Allineamento orizzontale della lista (default: lg:justify-end)listGap (stringa, opzionale): Spaziatura tra gli elementi della listaitemClasses (stringa, opzionale): Classi CSS per gli elementi della listaitemFontSize (stringa, opzionale): Dimensione del font per gli elementi principaliitemDropdownFontSize (stringa, opzionale): Dimensione del font per gli elementi del dropdownhasSearchPanel (booleano, opzionale): Mostra il pannello di ricerca mobilehasUserDropdown (booleano, opzionale): Mostra il componente @user-dropdown nel pannello mobile, sopra il form di ricercauserDropdown (oggetto, opzionale): Contesto passato a @user-dropdown; necessario se hasUserDropdown è truefirstLevels (array, obbligatorio): Elementi di primo livellolabel (stringa, obbligatorio): Etichetta dell’elementohasSubItems (booleano, opzionale): Indica se l’elemento ha sottomenuisCurrent (booleano, opzionale): Indica se l’elemento è la pagina correnteLivello AA — criteri pertinenti:
<nav>, <ul>, <li>, <a> semanticamente correttiaria-expanded riflette lo stato aperto/chiuso del menu mobile; aria-controls collega il trigger al pannello; aria-current="page" identifica la voce corrente<nav aria-label="Principale"> — identifica la regione di navigazione principale<button> con aria-expanded e aria-controls che punta al pannello (mainNavPanel)rtds-sr-onlyrole="search" e un button di ricerca con <span class="rtds-sr-only">Cerca</span>| Attributo | Valori | Condizione |
|---|---|---|
aria-label |
"Principale" |
sempre presente sul <nav> |
aria-expanded |
"true" / "false" |
presente sul button toggle mobile |
aria-controls |
"mainNavPanel" |
presente sul button toggle mobile |
aria-current |
"page" |
presente sull’<a> della voce corrente |
| Tasto | Azione |
|---|---|
Tab / Shift+Tab |
Sposta il focus tra i link di navigazione e i trigger dropdown |
Enter / Space |
Apre/chiude il menu mobile (sul toggle button) o attiva il link corrente |
| Frecce direzionali | Navigazione tra gli elementi dei dropdown (gestita dal componente dropdown-menu) |
Escape |
Chiude i dropdown aperti |
:focus-visible è sempre visibile e non viene rimosso via CSS<nav aria-label="Principale"> è annunciato come landmark di navigazione con etichetta “Principale”<button> toggle mobile ha aria-expanded — lo screen reader annuncia lo stato aperto/chiuso del pannello<span class="rtds-sr-only"> nel toggle (es. “Apri menu”) fornisce il nome accessibile del pulsante; l’icona SVG ha aria-hidden="true" e viene ignorataaria-current="page" sull’<a> della voce corrente — lo screen reader lo annuncia come “pagina corrente”<!-- Struttura base -->
<nav class="rtds-primary-navigation" aria-label="Principale" id="siteNavWrapper">
<button type="button" class="rtds-btn rtds-btn--only-text" aria-expanded="false" aria-controls="mainNavPanel">
<span class="rtds-sr-only">Apri menu</span>
<svg class="rtds-icon" aria-hidden="true" focusable="false"><use href="#solid--bars-3"></use></svg>
</button>
<div class="rtds-primary-navigation__panel" id="mainNavPanel">
<ul class="rtds-primary-navigation__list">
<li>
<a href="/home" aria-current="page">Home</a>
</li>
<li>
<a href="/argomenti">Argomenti</a>
</li>
</ul>
</div>
</nav>