<nav aria-labelledby="sidebarLabel" id="sideNav">
<h2 id="sidebarLabel" class="n7-content-05 pb-6 border-b n7-border-gray-01 text-base font-medium uppercase ">
Titolo navigazione
</h2>
<ul class="n7-side-navigation has-nav-dropdown">
<li class="n7-side-navigation__item bg-white flex flex-wrap items-stretch text-base font-medium is-current-trail">
<span class="is-first-level flex flex-1 is-current">
<a href="#" class="n7-nav-link flex flex-1 items-center gap-2 p-4 transition transition-all hover:n7-background-gray-02 hover:underline is-current" aria-current="page">
Current trail and current page
</a>
<button class="n7-nav-toggle flex items-center justify-center w-8 hover:n7-background-gray-02 group is-current" aria-expanded="true" aria-controls="sideNav-subnav-1">
<span class="sr-only">Dettaglio Current trail and current page</span>
<svg class="inline-block align-middle fill-current w-4 h-4 transition-all duration-200 ease-out group-aria-expanded:-rotate-180" aria-hidden="true" focusable="false" role="img">
<use xlink:href="../../icons.svg#mini--chevron-down" />
</svg>
</button>
</span>
<ul class="n7-side-navigation__submenu block w-full" id="sideNav-subnav-1">
<li>
<a href="" class="block p-4 transition bg-white text-sm xl:text-base hover:underline hover:n7-background-gray-02 focus:n7-background-gray-02">Subitem 2</a>
</li>
</ul>
</li>
<li class="n7-side-navigation__item bg-white flex flex-wrap items-stretch text-base font-medium is-current-trail">
<span class="is-first-level flex flex-1">
<a href="#" class="n7-nav-link flex flex-1 items-center gap-2 p-4 transition transition-all hover:n7-background-gray-02 hover:underline">
Current trail
</a>
<button class="n7-nav-toggle flex items-center justify-center w-8 hover:n7-background-gray-02 group " aria-expanded="true" aria-controls="sideNav-subnav-2">
<span class="sr-only">Dettaglio Current trail</span>
<svg class="inline-block align-middle fill-current w-4 h-4 transition-all duration-200 ease-out group-aria-expanded:-rotate-180" aria-hidden="true" focusable="false" role="img">
<use xlink:href="../../icons.svg#mini--chevron-down" />
</svg>
</button>
</span>
<ul class="n7-side-navigation__submenu block w-full" id="sideNav-subnav-2">
<li>
<a href="" class="block p-4 transition bg-white text-sm xl:text-base hover:underline hover:n7-background-gray-02 focus:n7-background-gray-02 is-current" aria-current="page">Subitem 1 current page</a>
</li>
</ul>
</li>
<li class="n7-side-navigation__item bg-white flex flex-wrap items-stretch text-base font-medium">
<span class="is-first-level flex flex-1">
<a href="#" class="n7-nav-link flex flex-1 items-center gap-2 p-4 transition transition-all hover:n7-background-gray-02 hover:underline">
Item 2
</a>
<button class="n7-nav-toggle flex items-center justify-center w-8 hover:n7-background-gray-02 group " aria-expanded="false" aria-controls="sideNav-subnav-3">
<span class="sr-only">Dettaglio Item 2</span>
<svg class="inline-block align-middle fill-current w-4 h-4 transition-all duration-200 ease-out group-aria-expanded:-rotate-180" aria-hidden="true" focusable="false" role="img">
<use xlink:href="../../icons.svg#mini--chevron-down" />
</svg>
</button>
</span>
<ul class="n7-side-navigation__submenu hidden w-full" id="sideNav-subnav-3">
<li>
<a href="" class="block p-4 transition bg-white text-sm xl:text-base hover:underline hover:n7-background-gray-02 focus:n7-background-gray-02">Subitem 2</a>
</li>
</ul>
</li>
<li class="n7-side-navigation__item bg-white flex flex-wrap items-stretch text-base font-medium">
<span class="is-first-level flex flex-1">
<a href="#" class="n7-nav-link flex flex-1 items-center gap-2 p-4 transition transition-all hover:n7-background-gray-02 hover:underline">
Item 4
</a>
</span>
</li>
<li class="n7-side-navigation__item bg-white flex flex-wrap items-stretch text-base font-medium">
<span class="is-first-level flex flex-1 is-current">
<a href="#" class="n7-nav-link flex flex-1 items-center gap-2 p-4 transition transition-all hover:n7-background-gray-02 hover:underline is-current" aria-current="page">
Item 5 current page
</a>
</span>
</li>
</ul>
</nav>
<nav aria-labelledby="{{ labelId }}"{% if id %} id="{{ id }}"{% endif %}>
<h2 id="{{ labelId }}" class="n7-content-05 pb-6 border-b n7-border-gray-01 text-base font-medium uppercase {% if hiddenLabel %} sr-only{% endif %}">
{{ label }}
</h2>
<ul class="n7-side-navigation has-nav-dropdown">
{% for firstLevel in firstLevels %}
<li class="n7-side-navigation__item bg-white flex flex-wrap items-stretch text-base font-medium{% if itemClasses %} {{ itemClasses }}{% endif %}{% if firstLevel.isCurrentTrail %} is-current-trail{% endif %}">
<span class="is-first-level flex flex-1{% if firstLevel.isCurrentPage %} is-current{% endif %}">
<a href="#" class="n7-nav-link flex flex-1 items-center gap-2 p-4 transition transition-all hover:n7-background-gray-02 hover:underline{% if firstLevelLinkClasses %} {{ firstLevelLinkClasses }}{% endif %}{% if firstLevel.isCurrentPage %} is-current{% endif %}"{% if firstLevel.isCurrentPage %} aria-current="page"{% endif %}>
{% if firstLevel.iconLeft %}
{% render '@icon--small', { id: firstLevel.iconLeft, size: 'w-4 h-4' }, true %}
{% endif %}
{{ firstLevel.label }}
</a>
{% if not firstLevel.subItems %}
</span>
{% endif %}
{% if firstLevel.subItems %}
<button
class="n7-nav-toggle flex items-center justify-center w-8 hover:n7-background-gray-02 group {% if firstLevel.isCurrentPage %} is-current{% endif %}"
aria-expanded="{% if firstLevel.isCurrentTrail %}true{% else %}false{% endif %}"
aria-controls="{{ id }}-subnav-{{ loop.index }}"
>
<span class="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: 'transition-all duration-200 ease-out group-aria-expanded:-rotate-180', size: 'w-4 h-4' }, true %}
</button>
</span>
<ul class="n7-side-navigation__submenu {% if firstLevel.isCurrentTrail %}block {% else %}hidden {% endif %}w-full{% if subnavClasses %} {{ subnavClasses }}{% endif %}" id="{{ id }}-subnav-{{ loop.index }}">
{% for item in firstLevel.subItems %}
<li>
<a href="" class="block p-4 transition bg-white text-sm xl:text-base hover:underline hover:n7-background-gray-02 focus:n7-background-gray-02{% if subnavLinkClasses %} {{ subnavLinkClasses }}{% endif %}{% if item.isCurrentPage %} is-current{% endif %}"{% if item.isCurrentPage %} aria-current="page"{% endif %}>{{ item.subitemLabel }}</a>
</li>
{% endfor %}
</ul>
{% endif %}
</li>
{% endfor %}
</ul>
</nav>
{
"label": "Titolo navigazione",
"labelId": "sidebarLabel",
"id": "sideNav",
"firstLevels": [
{
"label": "Current trail and current page",
"isCurrentTrail": true,
"isCurrentPage": true,
"subItems": [
{
"subitemLabel": "Subitem 2"
}
]
},
{
"label": "Current trail",
"isCurrentTrail": true,
"subItems": [
{
"subitemLabel": "Subitem 1 current page",
"isCurrentPage": true
}
]
},
{
"label": "Item 2",
"subItems": [
{
"subitemLabel": "Subitem 2"
}
]
},
{
"label": "Item 4"
},
{
"label": "Item 5 current page",
"isCurrentPage": true
}
]
}
/*
* 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 submenuDisclosure {
constructor(domNode) {
this.rootNode = domNode;
this.controlledNodes = [];
this.openIndex = null;
this.useArrowKeys = true;
this.topLevelNodes = [
...this.rootNode.querySelectorAll(
'.n7-nav-link, .n7-nav-toggle'
),
];
this.topLevelNodes.forEach((node) => {
// handle button + menu
if (
node.tagName.toLowerCase() === 'button' &&
node.hasAttribute('aria-controls')
) {
const menuLiParent = node.closest('li');
const menu = menuLiParent.querySelector('ul');
if (menu) {
// save ref controlled menu
this.controlledNodes.push(menu);
// collapse menus
// if(menuLiParent.classList.contains('is-current-trail','has-current-child')) {
if (menu.querySelector('.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));
}
}
// handle links
else {
this.controlledNodes.push(null);
node.addEventListener('keydown', this.onLinkKeyDown.bind(this));
}
});
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;
}
}
// public function to close open menu
close() {
this.toggleExpand(this.openIndex, false);
}
onBlur(event) {
var menuContainsFocus = this.rootNode.contains(event.relatedTarget);
if (!menuContainsFocus && this.openIndex !== null) {
this.toggleExpand(this.openIndex, false);
}
}
onButtonClick(event) {
var target = event.target;
// Check if the target is not a button but is a descendant of a button
if (target.tagName.toLowerCase() !== 'button') {
var buttonAncestor = findAncestor(target, 'button');
// If an ancestor button is found, trigger the click on that button
if (buttonAncestor) {
buttonAncestor.click();
return; // Stop further processing since the click is handled
}
}
var button = event.target;
var buttonIndex = this.topLevelNodes.indexOf(button);
var buttonExpanded = button.getAttribute('aria-expanded') === 'true';
this.toggleExpand(buttonIndex, !buttonExpanded);
console.log(event.target);
}
onButtonKeyDown(event) {
var targetButtonIndex = this.topLevelNodes.indexOf(document.activeElement);
// close on escape
if (event.key === 'Escape') {
this.toggleExpand(this.openIndex, false);
}
// move focus into the open menu if the current menu is open
else if (
this.useArrowKeys &&
this.openIndex === targetButtonIndex &&
event.key === 'ArrowDown'
) {
event.preventDefault();
this.controlledNodes[this.openIndex].querySelector('a').focus();
}
// handle arrow key navigation between top-level buttons, if set
else if (this.useArrowKeys) {
this.controlFocusByKey(event, this.topLevelNodes, targetButtonIndex);
}
}
onLinkKeyDown(event) {
var targetLinkIndex = this.topLevelNodes.indexOf(document.activeElement);
// handle arrow key navigation between top-level buttons, if set
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);
// close on escape
if (event.key === 'Escape') {
this.topLevelNodes[this.openIndex].focus();
this.toggleExpand(this.openIndex, false);
}
// handle arrow key navigation within menu links, if set
else if (this.useArrowKeys) {
this.controlFocusByKey(event, menuLinks, currentIndex);
}
}
toggleExpand(index, expanded) {
// close open menu, if applicable
if (this.openIndex !== index) {
this.toggleExpand(this.openIndex, false);
}
// handle menu at called index
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) {
domNode.style.display = show ? 'block' : 'none';
}
}
updateKeyControls(useArrowKeys) {
this.useArrowKeys = useArrowKeys;
}
}
/* Initialize Disclosure Menus */
window.addEventListener(
'load',
function () {
var menus = document.querySelectorAll('.has-nav-dropdown');
var disclosureMenus = [];
for (var i = 0; i < menus.length; i++) {
disclosureMenus[i] = new submenuDisclosure(menus[i]);
}
// listen to arrow key checkbox
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);
}
});
}
// fake link behavior
disclosureMenus.forEach((submenuDisclosure, i) => {
var links = menus[i].querySelectorAll('[href="#mythical-page-content"]');
var examplePageHeading = document.getElementById('mythical-page-heading');
for (var k = 0; k < links.length; k++) {
// The codepen export script updates the internal link href with a full URL
// we're just manually fixing that behavior here
links[k].href = '#mythical-page-content';
links[k].addEventListener('click', (event) => {
// change the heading text to fake a page change
var pageTitle = event.target.innerText;
examplePageHeading.innerText = pageTitle;
// handle aria-current
for (var n = 0; n < links.length; n++) {
links[n].removeAttribute('aria-current');
}
event.target.setAttribute('aria-current', 'page');
});
}
});
},
false
);
Sidebar navigation item. In the example, there are two current page, just for showing how configurations work, actually there will be just one is-current/current-page item.
Configurations: