<nav class="rtds-side-navigation " aria-labelledby="sidebarLabel" id="sideNav">
<span id="sidebarLabel" class="rtds-side-navigation__title rtds-sr-only md:rtds-not-sr-only md:rtds-pb-4 md:rtds-border-b md:rtds-border-gray-01">
<span class="rtds-side-navigation__label-context">Titolo della sezione</span>
<span class="rtds-block rtds-font-medium">Indice della sezione</span>
</span>
<button class="rtds-side-navigation__list-toggle rtds-nav-list-toggle md:rtds-hidden rtds-btn rtds-btn--icon-right rtds-btn--only-text rtds-btn--small rtds-group" aria-expanded="false" aria-controls="sideNavList">
<span class="rtds-grid rtds-gap-2 rtds-text-left">
<span class="rtds-side-navigation__label-context">Titolo della sezione</span>
<span>Indice della sezione</span>
</span>
<svg class="rtds-icon rtds-fill-current rtds-w-5 rtds-h-5" aria-hidden="true" focusable="false" role="img">
<use href="../../icons.svg#mini--chevron-up" />
</svg>
</button>
<ul class="rtds-nav-list rtds-side-navigation__list has-nav-dropdown" id="sideNavList">
<li class="rtds-side-navigation__item is-first-level is-current-trail">
<div class="rtds-flex rtds-items-center rtds-justify-between rtds-pb-2">
<a href="#" class="rtds-side-navigation__link rtds-nav-link rtds-font-bold rtds-text-lg is-current rtds-content-primary" aria-current="page">
<span class="rtds-side-navigation__label">
Current trail and current page
</span>
</a>
<button class="rtds-side-navigation__nav-toggle rtds-nav-toggle rtds-group rtds-ml-2 is-current rtds-content-primary" aria-expanded="true" aria-controls="sideNav-subnav-1">
<span class="rtds-sr-only">Dettaglio Current trail and current page</span>
<svg class="rtds-icon rtds-fill-current rtds-w-6 rtds-h-6 rtds-transition-all rtds-duration-200 rtds-ease-out group-aria-expanded:rtds-rotate-180" aria-hidden="true" focusable="false" role="img">
<use href="../../icons.svg#mini--chevron-down" />
</svg>
</button>
</div>
<ul class="rtds-side-navigation__submenu rtds-block rtds-w-full rtds-pl-4" id="sideNav-subnav-1">
<li class="rtds-side-navigation__item rtds-py-1">
<span class="rtds-side-navigation__second-level-label is-current rtds-flex rtds-items-center rtds-justify-between">
<a href="" class="rtds-side-navigation__link rtds-nav-link rtds-flex-grow rtds-font-bold rtds-text-base is-current rtds-content-primary" aria-current="page">
<span class="rtds-side-navigation__label">Subitem 2</span>
</a>
<button class="rtds-side-navigation__nav-toggle rtds-nav-toggle rtds-group rtds-ml-2 is-current rtds-content-primary" aria-expanded="false" aria-controls="sideNav-subsubnav--1">
<span class="rtds-sr-only">Dettaglio Subitem 2</span>
<svg class="rtds-icon rtds-fill-current rtds-w-6 rtds-h-6 rtds-transition-all rtds-duration-200 rtds-ease-out group-aria-expanded:rtds-rotate-180" aria-hidden="true" focusable="false" role="img">
<use href="../../icons.svg#mini--chevron-down" />
</svg>
</button>
</span>
<ul class="rtds-side-navigation__sub-submenu rtds-hidden rtds-w-full rtds-pl-4 rtds-space-y-2 rtds-mt-2" id="sideNav-subsubnav--1">
<li class="rtds-side-navigation__item">
<a href="" class="rtds-side-navigation__link rtds-nav-link rtds-pl-4 rtds-pt-0 rtds-pb-0 rtds-text-base rtds-content-03 ">
<span class="rtds-side-navigation__label">Sub-submenu</span>
</a>
</li>
<li class="rtds-side-navigation__item">
<a href="" class="rtds-side-navigation__link rtds-nav-link rtds-pl-4 rtds-pt-0 rtds-pb-0 rtds-text-base rtds-content-03 ">
<span class="rtds-side-navigation__label">sub-submenu 2</span>
</a>
</li>
</ul>
</li>
</ul>
</li>
<li class="rtds-side-navigation__item is-first-level is-current-trail">
<div class="rtds-flex rtds-items-center rtds-justify-between rtds-pb-2">
<a href="#" class="rtds-side-navigation__link rtds-nav-link rtds-font-bold rtds-text-lg">
<span class="rtds-side-navigation__label">
Current trail
</span>
</a>
<button class="rtds-side-navigation__nav-toggle rtds-nav-toggle rtds-group rtds-ml-2" aria-expanded="true" aria-controls="sideNav-subnav-2">
<span class="rtds-sr-only">Dettaglio Current trail</span>
<svg class="rtds-icon rtds-fill-current rtds-w-6 rtds-h-6 rtds-transition-all rtds-duration-200 rtds-ease-out group-aria-expanded:rtds-rotate-180" aria-hidden="true" focusable="false" role="img">
<use href="../../icons.svg#mini--chevron-down" />
</svg>
</button>
</div>
<ul class="rtds-side-navigation__submenu rtds-block rtds-w-full rtds-pl-4" id="sideNav-subnav-2">
<li class="rtds-side-navigation__item rtds-py-1">
<a href="" class="rtds-side-navigation__link rtds-nav-link rtds-font-bold rtds-text-base is-current rtds-content-primary " aria-current="page">
<span class="rtds-side-navigation__label">Subitem 1 current page</span>
</a>
</li>
</ul>
</li>
<li class="rtds-side-navigation__item is-first-level">
<div class="rtds-flex rtds-items-center rtds-justify-between rtds-pb-2">
<a href="#" class="rtds-side-navigation__link rtds-nav-link rtds-font-bold rtds-text-lg">
<span class="rtds-side-navigation__label">
Item 3
</span>
</a>
<button class="rtds-side-navigation__nav-toggle rtds-nav-toggle rtds-group rtds-ml-2" aria-expanded="false" aria-controls="sideNav-subnav-3">
<span class="rtds-sr-only">Dettaglio Item 3</span>
<svg class="rtds-icon rtds-fill-current rtds-w-6 rtds-h-6 rtds-transition-all rtds-duration-200 rtds-ease-out group-aria-expanded:rtds-rotate-180" aria-hidden="true" focusable="false" role="img">
<use href="../../icons.svg#mini--chevron-down" />
</svg>
</button>
</div>
<ul class="rtds-side-navigation__submenu rtds-hidden rtds-w-full rtds-pl-4" id="sideNav-subnav-3">
<li class="rtds-side-navigation__item rtds-py-1">
<a href="" class="rtds-side-navigation__link rtds-nav-link rtds-font-bold rtds-text-base">
<span class="rtds-side-navigation__label">Subitem 2</span>
</a>
</li>
<li class="rtds-side-navigation__item rtds-py-1">
<a href="" class="rtds-side-navigation__link rtds-nav-link rtds-font-bold rtds-text-base">
<span class="rtds-side-navigation__label">Item 4</span>
</a>
</li>
<li class="rtds-side-navigation__item rtds-py-1">
<span class="rtds-side-navigation__second-level-label rtds-flex rtds-items-center rtds-justify-between">
<a href="" class="rtds-side-navigation__link rtds-nav-link rtds-flex-grow rtds-font-bold rtds-text-base">
<span class="rtds-side-navigation__label">Item 5</span>
</a>
<button class="rtds-side-navigation__nav-toggle rtds-nav-toggle rtds-group rtds-ml-2" aria-expanded="false" aria-controls="sideNav-subsubnav--3">
<span class="rtds-sr-only">Dettaglio Item 5</span>
<svg class="rtds-icon rtds-fill-current rtds-w-6 rtds-h-6 rtds-transition-all rtds-duration-200 rtds-ease-out group-aria-expanded:rtds-rotate-180" aria-hidden="true" focusable="false" role="img">
<use href="../../icons.svg#mini--chevron-down" />
</svg>
</button>
</span>
<ul class="rtds-side-navigation__sub-submenu rtds-hidden rtds-w-full rtds-pl-4 rtds-space-y-2 rtds-mt-2" id="sideNav-subsubnav--3">
<li class="rtds-side-navigation__item">
<a href="" class="rtds-side-navigation__link rtds-nav-link rtds-pl-4 rtds-pt-0 rtds-pb-0 rtds-text-base rtds-content-03 ">
<span class="rtds-side-navigation__label">Sub-submenu</span>
</a>
</li>
<li class="rtds-side-navigation__item">
<a href="" class="rtds-side-navigation__link rtds-nav-link rtds-pl-4 rtds-pt-0 rtds-pb-0 rtds-text-base rtds-content-03 ">
<span class="rtds-side-navigation__label">sub-submenu 2</span>
</a>
</li>
</ul>
</li>
</ul>
</li>
<li class="rtds-side-navigation__item is-first-level">
<div class="rtds-flex rtds-items-center rtds-justify-between rtds-pb-2">
<a href="#" class="rtds-side-navigation__link rtds-nav-link rtds-font-bold rtds-text-lg">
<span class="rtds-side-navigation__label">
Item 4
</span>
</a>
</div>
</li>
</ul>
</nav>
<nav class="rtds-side-navigation{% block classes %} {% if classes %}{{ classes }}{% endif %}{% endblock %}" aria-labelledby="{{ labelId }}"{% if id %} id="{{ id }}"{% endif %}{% block attributes %}{% endblock %}>
<span id="{{ labelId }}" class="rtds-side-navigation__title{% if hiddenLabel %} rtds-sr-only{% else %} rtds-sr-only md:rtds-not-sr-only md:rtds-pb-4 md:rtds-border-b md:rtds-border-gray-01{% endif %}">
{% if labelContext %}<span class="rtds-side-navigation__label-context">{{ labelContext | safe }}</span>{% endif %}
<span class="rtds-block rtds-font-medium">{{ label | safe }}</span>
</span>
<button class="rtds-side-navigation__list-toggle rtds-nav-list-toggle md:rtds-hidden rtds-btn rtds-btn--icon-right rtds-btn--only-text rtds-btn--small rtds-group" aria-expanded="false" aria-controls="{{ listId }}">
<span class="rtds-grid rtds-gap-2 rtds-text-left">
{% if labelContext %}
<span class="rtds-side-navigation__label-context">{{ labelContext | safe }}</span>
{% endif %}
<span>{{ label | safe }}</span>
</span>
{% render '@icon--small', { id: 'mini--chevron-up', size: 'rtds-w-5 rtds-h-5' }, true %}
</button>
<ul class="rtds-nav-list rtds-side-navigation__list has-nav-dropdown" id="{{ listId }}">
{% for firstLevel in firstLevels %}
<li class="rtds-side-navigation__item is-first-level{% if itemClasses %} {{ itemClasses }}{% endif %}{% if firstLevel.isCurrentTrail %} is-current-trail{% endif %}">
<div class="rtds-flex rtds-items-center rtds-justify-between rtds-pb-2">
<a href="{% if firstLevel.href %}{{ firstLevel.href }}{% else %}#{% endif %}" class="rtds-side-navigation__link rtds-nav-link rtds-font-bold rtds-text-lg{% if firstLevelLinkClasses %} {{ firstLevelLinkClasses }}{% endif %}{% if firstLevel.isCurrentPage %} is-current rtds-content-primary{% endif %}"{% if firstLevel.isCurrentPage and not singlePage %} aria-current="page"{% endif %}>
<span class="rtds-side-navigation__label">
{% if firstLevel.iconLeft %}
{% render '@icon--small', { id: firstLevel.iconLeft, size: 'rtds-w-6 rtds-h-6' }, true %}
{% endif %}
{{ firstLevel.label }}
</span>
</a>
{% if firstLevel.subItems %}
<button
class="rtds-side-navigation__nav-toggle rtds-nav-toggle rtds-group rtds-ml-2{% if firstLevel.isCurrentPage %} is-current{% endif %}{% if firstLevel.isCurrentPage %} rtds-content-primary{% endif %}"
aria-expanded="{% if firstLevel.isCurrentTrail %}true{% else %}false{% endif %}"
aria-controls="{{ id }}-subnav-{{ loop.index }}"
>
<span class="rtds-sr-only">Dettaglio {{ firstLevel.label }}</span>
{% set buttonIcon = "" %}
{% if firstLevel.iconRight %}
{% set buttonIcon = firstLevel.iconRight %}
{% else %}
{% set buttonIcon = "mini--chevron-down" %}
{% endif %}
{% render '@icon--small', { id: buttonIcon, classes: 'rtds-transition-all rtds-duration-200 rtds-ease-out group-aria-expanded:rtds-rotate-180', size: 'rtds-w-6 rtds-h-6' }, true %}
</button>
{% endif %}
</div>
{% if firstLevel.subItems %}
<ul class="rtds-side-navigation__submenu{% if firstLevel.isCurrentTrail %} rtds-block{% else %} rtds-hidden{% endif %} rtds-w-full rtds-pl-4{% if subnavClasses %} {{ subnavClasses }}{% endif %}" id="{{ id }}-subnav-{{ loop.index }}">
{% for item in firstLevel.subItems %}
<li class="rtds-side-navigation__item{% if item.isCurrentTrail %} is-current-trail{% endif %} rtds-py-1">
{% if item.subSubItems %}
<span class="rtds-side-navigation__second-level-label{% if item.isCurrentPage %} is-current{% endif %} rtds-flex rtds-items-center rtds-justify-between">
<a href="" class="rtds-side-navigation__link rtds-nav-link rtds-flex-grow rtds-font-bold rtds-text-base{% if subnavLinkClasses %} {{ subnavLinkClasses }}{% endif %}{% if item.isCurrentPage %} is-current rtds-content-primary{% endif %}"{% if item.isCurrentPage %} aria-current="page"{% endif %}>
<span class="rtds-side-navigation__label">{{ item.subitemLabel }}</span>
</a>
<button
class="rtds-side-navigation__nav-toggle rtds-nav-toggle rtds-group rtds-ml-2{% if item.isCurrentPage %} is-current{% endif %}{% if item.isCurrentPage %} rtds-content-primary{% endif %}"
aria-expanded="{% if item.isCurrentTrail %}true{% else %}false{% endif %}"
aria-controls="{{ id }}-subsubnav-{{ loop.parent.loop.index }}-{{ loop.index }}"
>
<span class="rtds-sr-only">Dettaglio {{ item.subitemLabel }}</span>
{% render '@icon--small', { id: 'mini--chevron-down', classes: 'rtds-transition-all rtds-duration-200 rtds-ease-out group-aria-expanded:rtds-rotate-180', size: 'rtds-w-6 rtds-h-6' }, true %}
</button>
</span>
<ul class="rtds-side-navigation__sub-submenu{% if item.isCurrentTrail %} rtds-block{% else %} rtds-hidden{% endif %} rtds-w-full rtds-pl-4 rtds-space-y-2 rtds-mt-2" id="{{ id }}-subsubnav-{{ loop.parent.loop.index }}-{{ loop.index }}">
{% for subSubItem in item.subSubItems %}
<li class="rtds-side-navigation__item">
<a href="" class="rtds-side-navigation__link rtds-nav-link rtds-pl-4 rtds-pt-0 rtds-pb-0 rtds-text-base rtds-content-03 {% if subSubItem.isCurrentPage %} rtds-content-primary is-current{% endif %}"{% if subSubItem.isCurrentPage %} aria-current="page"{% endif %}>
<span class="rtds-side-navigation__label">{{ subSubItem.label }}</span>
</a>
</li>
{% endfor %}
</ul>
{% else %}
<a href="" class="rtds-side-navigation__link rtds-nav-link rtds-font-bold rtds-text-base{% if subnavLinkClasses %} {{ subnavLinkClasses }}{% endif %}{% if item.isCurrentPage %} is-current rtds-content-primary {% endif %}"{% if item.isCurrentPage %} aria-current="page"{% endif %}>
<span class="rtds-side-navigation__label">{{ item.subitemLabel }}</span>
</a>
{% endif %}
</li>
{% endfor %}
</ul>
{% endif %}
</li>
{% endfor %}
</ul>
</nav>
{
"label": "Indice della sezione",
"labelId": "sidebarLabel",
"id": "sideNav",
"listId": "sideNavList",
"firstLevels": [
{
"label": "Current trail and current page",
"isCurrentTrail": true,
"isCurrentPage": true,
"subItems": [
{
"subitemLabel": "Subitem 2",
"isCurrentPage": true,
"subSubItems": [
{
"label": "Sub-submenu"
},
{
"label": "sub-submenu 2"
}
]
}
]
},
{
"label": "Current trail",
"isCurrentTrail": true,
"subItems": [
{
"subitemLabel": "Subitem 1 current page",
"isCurrentPage": true
}
]
},
{
"label": "Item 3",
"subItems": [
{
"subitemLabel": "Subitem 2"
},
{
"subitemLabel": "Item 4"
},
{
"subitemLabel": "Item 5",
"subSubItems": [
{
"label": "Sub-submenu"
},
{
"label": "sub-submenu 2"
}
]
}
]
},
{
"label": "Item 4"
}
],
"labelContext": "Titolo della sezione"
}
/**
* SIDE NAVIGATION
* Supporta sia vertical che horizontal tramite modifier class
*/
@layer components {
/* ============================================
BASE STYLES - Common to all layouts
============================================ */
.rtds-side-navigation__title {
@apply rtds-grid rtds-gap-3 rtds-content-03 rtds-text-base rtds-font-bold;
}
.rtds-side-navigation__label-context {
@apply rtds-text-lg md:rtds-text-xl lg:rtds-text-2xl rtds-block rtds-heading-3 rtds-content-01;
}
.rtds-side-navigation__item {
@apply rtds-content-03 rtds-bg-white rtds-flex rtds-flex-wrap rtds-items-stretch rtds-text-base;
}
.rtds-side-navigation__first-level-label {
@apply rtds-flex rtds-flex-1 rtds-font-bold;
}
.rtds-side-navigation__link {
@apply rtds-text-current rtds-border-transparent rtds-flex rtds-flex-1 rtds-items-center rtds-gap-2 rtds-p-4 rtds-transition hover:rtds-content-primary hover:rtds-underline;
}
.rtds-side-navigation__label {
@apply rtds-inline-block;
}
.rtds-side-navigation__link:where(.is-current) {
@apply rtds-content-primary rtds-border-current;
}
:where(.rtds-side-navigation__link.is-current) .rtds-side-navigation__label {
@apply rtds-pb-1 rtds-border-b-2 rtds-border-current;
}
.rtds-side-navigation__nav-toggle {
@apply rtds-flex rtds-items-center rtds-justify-center rtds-w-8 hover:rtds-content-primary;
}
/* MOBILE */
.rtds-side-navigation__list-toggle {
@apply rtds-w-full rtds-justify-between rtds-items-end rtds-pl-0 rtds-border-y-0 rtds-border-l-0 rtds-border-r-0 rtds-border-b rtds-rounded-none rtds-border-gray-01 rtds-font-medium rtds-content-03 rtds-text-sm md:rtds-text-base hover:rtds-bg-white focus:rtds-bg-white hover:rtds-border-gray-02;
}
.rtds-side-navigation__list-toggle:where([aria-expanded="false"]) .rtds-icon {
@apply -rtds-rotate-180;
}
.rtds-side-navigation__list-toggle:where([aria-expanded="false"]) ~ .rtds-side-navigation__list {
@apply rtds-hidden md:rtds-block;
}
/* sub-navigation */
.rtds-side-navigation__submenu {
@apply rtds-pl-4;
}
/* ============================================
HORIZONTAL MODIFIER - Layout orizzontale da MD
============================================ */
.rtds-side-navigation--horizontal {
@screen md {
/* Title nascosto per horizontal */
.rtds-side-navigation__title {
@apply rtds-sr-only;
}
/* Lista: flex horizontal */
.rtds-side-navigation__list {
@apply rtds-flex rtds-flex-wrap rtds-gap-0 rtds-py-4 rtds-border-t-0;
}
/* Items: no wrap, posizione relativa */
.rtds-side-navigation__item {
@apply rtds-flex-nowrap rtds-relative;
}
/* First level label: inline con toggle */
.rtds-side-navigation__first-level-label {
@apply rtds-flex rtds-items-center;
}
/* Link: padding ridotto, border-bottom, no underline */
.rtds-side-navigation__link {
@apply rtds-mx-4 rtds-px-2 rtds-py-0 rtds-text-sm md:rtds-text-base rtds-font-semibold rtds-border-b-2 rtds-border-transparent hover:rtds-border-primary hover:rtds-no-underline;
}
.rtds-side-navigation__link:where(.is-current) {
@apply rtds-border-primary rtds-content-primary;
}
:where(.rtds-side-navigation__link.is-current) .rtds-side-navigation__label {
@apply rtds-pb-0 rtds-border-b-0;
}
/* Toggle button per horizontal */
.rtds-side-navigation__nav-toggle {
@apply rtds-px-2 rtds-py-2 rtds-w-auto;
}
/* Submenu: dropdown assoluto */
.rtds-side-navigation__submenu {
@apply rtds-absolute rtds-top-full rtds-left-0 rtds-min-w-[200px] rtds-pl-0 rtds-bg-white rtds-border rtds-border-gray-01 rtds-shadow-lg rtds-z-10;
}
/* Submenu items */
.rtds-side-navigation__submenu .rtds-side-navigation__item {
@apply rtds-w-full rtds-flex-wrap;
}
/* Submenu links con hover background */
.rtds-side-navigation__submenu .rtds-side-navigation__link {
@apply rtds-mx-0 rtds-px-6 rtds-py-3 rtds-text-sm rtds-border-b-0 hover:rtds-background-01 hover:rtds-border-transparent;
}
/* Submenu link corrente con background */
.rtds-side-navigation__submenu .rtds-side-navigation__link:where(.is-current) {
@apply rtds-background-02 rtds-font-medium rtds-border-transparent;
}
.rtds-side-navigation__submenu .rtds-side-navigation__link:where(.is-current) .rtds-side-navigation__label {
@apply rtds-border-b-0;
}
}
}
/* ============================================
ANCHOR NAVIGATION
============================================ */
.rtds-side-navigation--anchor {
@apply rtds-scroll-m-[--header-height] md:rtds-scroll-m-0;
}
:where(.rtds-side-navigation--anchor) .rtds-side-navigation__link {
@apply rtds-border-b-0 rtds-border-l-4;
}
:where(.rtds-side-navigation--anchor .rtds-side-navigation__link.is-current) .rtds-side-navigation__label {
@apply rtds-pb-0 rtds-border-b-0;
}
/* Anchor + horizontal: usa border-bottom */
.rtds-side-navigation--anchor.rtds-side-navigation--horizontal {
@screen md {
:where(.rtds-side-navigation__link) {
@apply rtds-border-l-0 rtds-border-b-2;
}
}
}
}
'use strict';
/**
* SIDE NAVIGATION - JavaScript
* Gestisce sia vertical che horizontal navigation
* Supporta keyboard navigation, ESC key, e focus management
*/
// 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 submenuDisclosure {
constructor(domNode) {
this.rootNode = domNode;
this.parentNav = domNode.closest('.rtds-side-navigation');
this.isHorizontal = this.parentNav?.classList.contains('rtds-side-navigation--horizontal');
this.controlledNodes = [];
this.openIndex = null;
this.useArrowKeys = true;
// Trova tutti i link e toggle button di primo livello
this.topLevelNodes = [
...this.rootNode.querySelectorAll('.rtds-nav-link, .rtds-nav-toggle'),
];
this.init();
}
init() {
this.topLevelNodes.forEach((node) => {
// Gestisci button + menu
if (
node.tagName.toLowerCase() === 'button' &&
node.hasAttribute('aria-controls')
) {
const menuLiParent = node.closest('li');
const menu = menuLiParent.querySelector('ul');
if (menu) {
// Salva riferimento al menu controllato
this.controlledNodes.push(menu);
// Inizializza stato (aperto se current trail, chiuso altrimenti)
if (menu.querySelector('.is-current') || node.classList.contains('is-current')) {
node.setAttribute('aria-expanded', 'true');
this.toggleMenu(menu, true);
} else {
node.setAttribute('aria-expanded', 'false');
this.toggleMenu(menu, false);
}
// Attach event listeners
menu.addEventListener('keydown', this.onMenuKeyDown.bind(this));
node.addEventListener('click', this.onButtonClick.bind(this));
node.addEventListener('keydown', this.onButtonKeyDown.bind(this));
}
}
// Gestisci link semplici
else {
this.controlledNodes.push(null);
node.addEventListener('keydown', this.onLinkKeyDown.bind(this));
}
});
// Riferimento al toggle button principale (mobile)
this.mainMenuToggle = this.parentNav?.querySelector('.rtds-nav-list-toggle');
// ESC chiude il menu principale su mobile
this.rootNode.addEventListener('keydown', (event) => {
if (event.key === 'Escape' && window.innerWidth < 768) {
if (this.mainMenuToggle?.getAttribute('aria-expanded') === 'true') {
this.mainMenuToggle.setAttribute('aria-expanded', 'false');
this.mainMenuToggle.focus();
}
}
});
}
// Gestisce navigazione con arrow keys
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;
}
}
// Chiude il submenu aperto
close() {
this.toggleExpand(this.openIndex, false);
}
// Click su toggle button
onButtonClick(event) {
var target = event.target;
if (target.tagName.toLowerCase() !== 'button') {
var buttonAncestor = findAncestor(target, 'button');
if (buttonAncestor) {
buttonAncestor.click();
return;
}
}
var button = event.currentTarget;
var buttonIndex = this.topLevelNodes.indexOf(button);
var buttonExpanded = button.getAttribute('aria-expanded') === 'true';
this.toggleExpand(buttonIndex, !buttonExpanded);
}
// Keyboard events su toggle button
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);
}
}
// Keyboard events su link semplici
onLinkKeyDown(event) {
var targetLinkIndex = this.topLevelNodes.indexOf(document.activeElement);
if (this.useArrowKeys) {
this.controlFocusByKey(event, this.topLevelNodes, targetLinkIndex);
}
}
// Keyboard events nel submenu
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);
}
}
// Apre/chiude submenu
toggleExpand(index, expanded) {
// Chiudi altri submenu aperti
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);
}
}
// Mostra/nascondi menu
toggleMenu(domNode, show) {
if (domNode) {
domNode.style.display = show ? 'block' : 'none';
}
}
// Abilita/disabilita arrow keys
updateKeyControls(useArrowKeys) {
this.useArrowKeys = useArrowKeys;
}
}
/* Initialize Disclosure Menus */
window.addEventListener('load', function () {
// Toggle per mobile menu
const navListToggle = document.querySelector('.rtds-nav-list-toggle');
if (navListToggle) {
navListToggle.addEventListener('click', function() {
const currentState = this.getAttribute('aria-expanded') === 'true';
this.setAttribute('aria-expanded', (!currentState).toString());
});
// Mantieni menu aperto durante scroll up su mobile
let lastScrollTop = 0;
window.addEventListener('scroll', function() {
const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
if (scrollTop < lastScrollTop && navListToggle.getAttribute('aria-expanded') === 'true') {
navListToggle.setAttribute('aria-expanded', 'true');
}
lastScrollTop = scrollTop;
});
}
// Inizializza tutti i menu con dropdown
var dropdownMenus = document.querySelectorAll('.has-nav-dropdown');
var disclosureMenus = [];
for (var i = 0; i < dropdownMenus.length; i++) {
disclosureMenus[i] = new submenuDisclosure(dropdownMenus[i]);
}
// Optional: switch per abilitare/disabilitare arrow keys
var arrowKeySwitch = document.getElementById('arrow-behavior-switch');
if (arrowKeySwitch) {
arrowKeySwitch.addEventListener('change', function () {
var checked = arrowKeySwitch.checked;
for (var i = 0; i < disclosureMenus.length; i++) {
disclosureMenus[i].updateKeyControls(checked);
}
});
}
}, false);
Component for sidebar navigation. It can be used as multipage navigation or as anchor navigation.
For multipage navigation, current page link must have aria-current=”page” attribute.
It can be displayed using a label (that could be the section title or page title if anchor), or a context label ( section title or page title if anchor) and a label (eg “Indice della pagina”, “Indice della sezione”), if more context is needed and visually, a more highlighted title is needed.
For responsive behaviour, the component has a toggle button, hidden on desktop. Button label depends on the context label and navigation label: if a context label is present, it will be used as button label altogheter with the navigation label, otherwise the navigation label will be used, as shown in the examples.
In the complete example, there are:
Configurations: