diff --git a/src/Symfony/Component/ErrorHandler/Resources/assets/js/exception.js b/src/Symfony/Component/ErrorHandler/Resources/assets/js/exception.js index 95b8ea17197c9..22ce675dfb7d2 100644 --- a/src/Symfony/Component/ErrorHandler/Resources/assets/js/exception.js +++ b/src/Symfony/Component/ErrorHandler/Resources/assets/js/exception.js @@ -39,23 +39,31 @@ } (function createTabs() { + /* the accessibility options of this component have been defined according to: */ + /* www.w3.org/WAI/ARIA/apg/example-index/tabs/tabs-manual.html */ var tabGroups = document.querySelectorAll('.sf-tabs:not([data-processed=true])'); /* create the tab navigation for each group of tabs */ for (var i = 0; i < tabGroups.length; i++) { var tabs = tabGroups[i].querySelectorAll(':scope > .tab'); - var tabNavigation = document.createElement('ul'); + var tabNavigation = document.createElement('div'); tabNavigation.className = 'tab-navigation'; + tabNavigation.setAttribute('role', 'tablist'); var selectedTabId = 'tab-' + i + '-0'; /* select the first tab by default */ for (var j = 0; j < tabs.length; j++) { var tabId = 'tab-' + i + '-' + j; var tabTitle = tabs[j].querySelector('.tab-title').innerHTML; - var tabNavigationItem = document.createElement('li'); + var tabNavigationItem = document.createElement('button'); + addClass(tabNavigationItem, 'tab-control'); tabNavigationItem.setAttribute('data-tab-id', tabId); + tabNavigationItem.setAttribute('role', 'tab'); + tabNavigationItem.setAttribute('aria-controls', tabId); if (hasClass(tabs[j], 'active')) { selectedTabId = tabId; } - if (hasClass(tabs[j], 'disabled')) { addClass(tabNavigationItem, 'disabled'); } + if (hasClass(tabs[j], 'disabled')) { + addClass(tabNavigationItem, 'disabled'); + } tabNavigationItem.innerHTML = tabTitle; tabNavigation.appendChild(tabNavigationItem); @@ -69,24 +77,31 @@ /* display the active tab and add the 'click' event listeners */ for (i = 0; i < tabGroups.length; i++) { - tabNavigation = tabGroups[i].querySelectorAll(':scope >.tab-navigation li'); + tabNavigation = tabGroups[i].querySelectorAll(':scope > .tab-navigation .tab-control'); for (j = 0; j < tabNavigation.length; j++) { tabId = tabNavigation[j].getAttribute('data-tab-id'); - document.getElementById(tabId).querySelector('.tab-title').className = 'hidden'; + var tabPanel = document.getElementById(tabId); + tabPanel.setAttribute('role', 'tabpanel'); + tabPanel.setAttribute('aria-labelledby', tabId); + tabPanel.querySelector('.tab-title').className = 'hidden'; if (hasClass(tabNavigation[j], 'active')) { - document.getElementById(tabId).className = 'block'; + tabPanel.className = 'block'; + tabNavigation[j].setAttribute('aria-selected', 'true'); + tabNavigation[j].removeAttribute('tabindex'); } else { - document.getElementById(tabId).className = 'hidden'; + tabPanel.className = 'hidden'; + tabNavigation[j].removeAttribute('aria-selected'); + tabNavigation[j].setAttribute('tabindex', '-1'); } tabNavigation[j].addEventListener('click', function(e) { var activeTab = e.target || e.srcElement; /* needed because when the tab contains HTML contents, user can click */ - /* on any of those elements instead of their parent '
  • ' element */ - while (activeTab.tagName.toLowerCase() !== 'li') { + /* on any of those elements instead of their parent '