Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit a8ad6bb

Browse files
committed
feature #48762 [WebProfilerBundle] Improve accessibility of tabs and some links (javiereguiluz)
This PR was squashed before being merged into the 6.3 branch. Discussion ---------- [WebProfilerBundle] Improve accessibility of tabs and some links | Q | A | ------------- | --- | Branch? | 6.3 | Bug fix? | no | New feature? | no | Deprecations? | no | Tickets | - | License | MIT | Doc PR | - This improves Profiler accessibility a bit by: * Showing an outline in "link buttons" when navigating with the keyboard * Adding full ARIA attributes to our tabs, which are common in many panels Commits ------- efc9723 [WebProfilerBundle] Improve accessibility of tabs and some links
2 parents f65e098 + efc9723 commit a8ad6bb

File tree

3 files changed

+55
-32
lines changed

3 files changed

+55
-32
lines changed

src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/logger.html.twig

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -55,28 +55,28 @@
5555
{% set filters = collector.filters %}
5656
<div class="log-filters">
5757
<div id="log-filter-type" class="log-filter">
58-
<ul class="tab-navigation">
59-
<li class="{{ not has_error_logs and not has_deprecation_logs ? 'active' }}">
58+
<div class="tab-navigation" role="tablist">
59+
<button role="tab" class="tab-control {{ not has_error_logs and not has_deprecation_logs ? 'active' }}">
6060
<input {{ not has_error_logs and not has_deprecation_logs ? 'checked' }} type="radio" id="filter-log-type-all" name="filter-log-type" value="all">
6161
<label for="filter-log-type-all">All messages</label>
62-
</li>
62+
</button>
6363

64-
<li class="{{ has_error_logs ? 'active' }}">
64+
<button role="tab" class="tab-control {{ has_error_logs ? 'active' }}">
6565
<input {{ has_error_logs ? 'checked' }} type="radio" id="filter-log-type-error" name="filter-log-type" value="error">
6666
<label for="filter-log-type-error">
6767
Errors
6868
<span class="badge status-{{ collector.counterrors ? 'error' }}">{{ collector.counterrors|default(0) }}</span>
6969
</label>
70-
</li>
70+
</button>
7171

72-
<li class="{{ not has_error_logs and has_deprecation_logs ? 'active' }}">
72+
<button role="tab" class="tab-control {{ not has_error_logs and has_deprecation_logs ? 'active' }}">
7373
<input {{ not has_error_logs and has_deprecation_logs ? 'checked' }} type="radio" id="filter-log-type-deprecation" name="filter-log-type" value="deprecation">
7474
<label for="filter-log-type-deprecation">
7575
Deprecations
7676
<span class="badge status-{{ collector.countdeprecations ? 'warning' }}">{{ collector.countdeprecations|default(0) }}</span>
7777
</label>
78-
</li>
79-
</ul>
78+
</button>
79+
</div>
8080
</div>
8181

8282
<details id="log-filter-priority" class="log-filter">

src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/base_js.html.twig

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -663,23 +663,31 @@ if (typeof Sfjs === 'undefined' || typeof Sfjs.loadToolbar === 'undefined') {
663663
},
664664
665665
createTabs: function() {
666+
/* the accessibility options of this component have been defined according to: */
667+
/* www.w3.org/WAI/ARIA/apg/example-index/tabs/tabs-manual.html */
666668
var tabGroups = document.querySelectorAll('.sf-tabs:not([data-processed=true])');
667669
668670
/* create the tab navigation for each group of tabs */
669671
for (var i = 0; i < tabGroups.length; i++) {
670672
var tabs = tabGroups[i].querySelectorAll(':scope > .tab');
671-
var tabNavigation = document.createElement('ul');
673+
var tabNavigation = document.createElement('div');
672674
tabNavigation.className = 'tab-navigation';
675+
tabNavigation.setAttribute('role', 'tablist');
673676
674677
var selectedTabId = 'tab-' + i + '-0'; /* select the first tab by default */
675678
for (var j = 0; j < tabs.length; j++) {
676679
var tabId = 'tab-' + i + '-' + j;
677680
var tabTitle = tabs[j].querySelector('.tab-title').innerHTML;
678681
679-
var tabNavigationItem = document.createElement('li');
682+
var tabNavigationItem = document.createElement('button');
683+
tabNavigationItem.classList.add('tab-control');
680684
tabNavigationItem.setAttribute('data-tab-id', tabId);
685+
tabNavigationItem.setAttribute('role', 'tab');
686+
tabNavigationItem.setAttribute('aria-controls', tabId);
681687
if (hasClass(tabs[j], 'active')) { selectedTabId = tabId; }
682-
if (hasClass(tabs[j], 'disabled')) { addClass(tabNavigationItem, 'disabled'); }
688+
if (hasClass(tabs[j], 'disabled')) {
689+
addClass(tabNavigationItem, 'disabled');
690+
}
683691
tabNavigationItem.innerHTML = tabTitle;
684692
tabNavigation.appendChild(tabNavigationItem);
685693
@@ -693,24 +701,31 @@ if (typeof Sfjs === 'undefined' || typeof Sfjs.loadToolbar === 'undefined') {
693701
694702
/* display the active tab and add the 'click' event listeners */
695703
for (i = 0; i < tabGroups.length; i++) {
696-
tabNavigation = tabGroups[i].querySelectorAll(':scope > .tab-navigation li');
704+
tabNavigation = tabGroups[i].querySelectorAll(':scope > .tab-navigation .tab-control');
697705
698706
for (j = 0; j < tabNavigation.length; j++) {
699707
tabId = tabNavigation[j].getAttribute('data-tab-id');
700-
document.getElementById(tabId).querySelector('.tab-title').className = 'hidden';
708+
const tabPanel = document.getElementById(tabId);
709+
tabPanel.setAttribute('role', 'tabpanel');
710+
tabPanel.setAttribute('aria-labelledby', tabId);
711+
tabPanel.querySelector('.tab-title').className = 'hidden';
701712
702713
if (hasClass(tabNavigation[j], 'active')) {
703-
document.getElementById(tabId).className = 'block';
714+
tabPanel.className = 'block';
715+
tabNavigation[j].setAttribute('aria-selected', 'true');
716+
tabNavigation[j].removeAttribute('tabindex');
704717
} else {
705-
document.getElementById(tabId).className = 'hidden';
718+
tabPanel.className = 'hidden';
719+
tabNavigation[j].removeAttribute('aria-selected');
720+
tabNavigation[j].setAttribute('tabindex', '-1');
706721
}
707722
708723
tabNavigation[j].addEventListener('click', function(e) {
709724
var activeTab = e.target || e.srcElement;
710725
711726
/* needed because when the tab contains HTML contents, user can click */
712-
/* on any of those elements instead of their parent '<li>' element */
713-
while (activeTab.tagName.toLowerCase() !== 'li') {
727+
/* on any of those elements instead of their parent '<button>' element */
728+
while (activeTab.tagName.toLowerCase() !== 'button') {
714729
activeTab = activeTab.parentNode;
715730
}
716731
@@ -720,9 +735,13 @@ if (typeof Sfjs === 'undefined' || typeof Sfjs.loadToolbar === 'undefined') {
720735
var tabId = tabNavigation[k].getAttribute('data-tab-id');
721736
document.getElementById(tabId).className = 'hidden';
722737
removeClass(tabNavigation[k], 'active');
738+
tabNavigation[k].removeAttribute('aria-selected');
739+
tabNavigation[k].setAttribute('tabindex', '-1');
723740
}
724741
725742
addClass(activeTab, 'active');
743+
activeTab.setAttribute('aria-selected', 'true');
744+
activeTab.removeAttribute('tabindex');
726745
var activeTabId = activeTab.getAttribute('data-tab-id');
727746
document.getElementById(activeTabId).className = 'block';
728747
});
@@ -892,7 +911,7 @@ if (typeof Sfjs === 'undefined' || typeof Sfjs.loadToolbar === 'undefined') {
892911
document.querySelector('#log-filter-channel .filter-active-num').innerText = (channels.length === selectedChannels.length) ? 'All' : selectedChannels.length;
893912
894913
/* update the currently selected "log type" tab */
895-
document.querySelectorAll('#log-filter-type li').forEach((tab) => tab.classList.remove('active'));
914+
document.querySelectorAll('#log-filter-type .tab-control').forEach((tab) => tab.classList.remove('active'));
896915
document.querySelector(`#log-filter-type input[value="${selectedType}"]`).parentElement.classList.add('active');
897916
},
898917
};

src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/profiler.css.twig

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -519,7 +519,6 @@ input[type="radio"], input[type="checkbox"] {
519519
color: var(--color-link);
520520
text-decoration: none;
521521
background-color: transparent;
522-
outline: none;
523522
border: 0;
524523
padding: 0;
525524
cursor: pointer;
@@ -1551,23 +1550,26 @@ tr.status-warning td {
15511550
box-shadow: inset 0 0 0 1px var(--tab-border-color), 0 0 0 4px var(--page-background);
15521551
margin: 0 0 10px;
15531552
}
1554-
.tab-navigation li {
1553+
.tab-navigation .tab-control {
1554+
background: transparent;
1555+
border: 0;
15551556
box-shadow: none;
15561557
transition: box-shadow .05s ease-in, background-color .05s ease-in;
15571558
cursor: pointer;
1559+
font-size: 14px;
15581560
font-weight: 500;
1559-
list-style: none;
1561+
line-height: 1.4;
15601562
margin: 0;
15611563
padding: 4px 14px;
15621564
position: relative;
15631565
text-align: center;
15641566
z-index: 1;
15651567
}
1566-
.sf-tabs-sm .tab-navigation li {
1568+
.sf-tabs-sm .tab-navigation .tab-control {
15671569
font-size: 13px;
15681570
padding: 2.5px 10px;
15691571
}
1570-
.tab-navigation li:before {
1572+
.tab-navigation .tab-control:before {
15711573
background: var(--tab-border-color);
15721574
bottom: 15%;
15731575
content: "";
@@ -1576,10 +1578,12 @@ tr.status-warning td {
15761578
top: 15%;
15771579
width: 1px;
15781580
}
1579-
.tab-navigation li:first-child:before, .tab-navigation li.active + li:before, .tab-navigation li.active:before {
1581+
.tab-navigation .tab-control:first-child:before,
1582+
.tab-navigation .tab-control.active + .tab-control:before,
1583+
.tab-navigation .tab-control.active:before {
15801584
width: 0;
15811585
}
1582-
.tab-navigation li .badge {
1586+
.tab-navigation .tab-control .badge {
15831587
background: var(--selected-badge-background);
15841588
box-shadow: var(--selected-badge-shadow);
15851589
color: var(--selected-badge-color);
@@ -1593,29 +1597,29 @@ tr.status-warning td {
15931597
text-align: center;
15941598
white-space: nowrap;
15951599
}
1596-
.tab-navigation li.disabled {
1600+
.tab-navigation .tab-control.disabled {
15971601
color: var(--tab-disabled-color);
15981602
}
1599-
.tab-navigation li.active {
1603+
.tab-navigation .tab-control.active {
16001604
background-color: var(--tab-active-background);
16011605
border-radius: 6px;
16021606
box-shadow: inset 0 0 0 1.5px var(--tab-active-border-color);
16031607
color: var(--tab-active-color);
16041608
position: relative;
16051609
z-index: 1;
16061610
}
1607-
.theme-dark .tab-navigation li.active {
1611+
.theme-dark .tab-navigation .tab-control.active {
16081612
box-shadow: inset 0 0 0 1px var(--tab-border-color);
16091613
}
16101614
.tab-content > *:first-child {
16111615
margin-top: 0;
16121616
}
1613-
.tab-navigation li .badge.status-warning {
1617+
.tab-navigation .tab-control .badge.status-warning {
16141618
background: var(--selected-badge-warning-background);
16151619
box-shadow: var(--selected-badge-warning-shadow);
16161620
color: var(--selected-badge-warning-color);
16171621
}
1618-
.tab-navigation li .badge.status-error {
1622+
.tab-navigation .tab-control .badge.status-error {
16191623
background: var(--selected-badge-danger-background);
16201624
box-shadow: var(--selected-badge-danger-shadow);
16211625
color: var(--selected-badge-danger-color);
@@ -1789,10 +1793,10 @@ tr.status-warning td {
17891793
font-weight: bold;
17901794
padding: 0 1px;
17911795
}
1792-
.log-filter .tab-navigation li input {
1796+
.log-filter .tab-navigation .tab-control input {
17931797
display: none;
17941798
}
1795-
.log-filter .tab-navigation li label {
1799+
.log-filter .tab-navigation .tab-control label {
17961800
cursor: pointer;
17971801
}
17981802
.log-filters .log-filter .log-filter-content {

0 commit comments

Comments
 (0)