Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WebProfilerBundle] Improve accessibility of tabs and some links #48762

Merged
merged 1 commit into from
Jan 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -55,28 +55,28 @@
{% set filters = collector.filters %}
<div class="log-filters">
<div id="log-filter-type" class="log-filter">
<ul class="tab-navigation">
<li class="{{ not has_error_logs and not has_deprecation_logs ? 'active' }}">
<div class="tab-navigation" role="tablist">
<button role="tab" class="tab-control {{ not has_error_logs and not has_deprecation_logs ? 'active' }}">
<input {{ not has_error_logs and not has_deprecation_logs ? 'checked' }} type="radio" id="filter-log-type-all" name="filter-log-type" value="all">
<label for="filter-log-type-all">All messages</label>
</li>
</button>

<li class="{{ has_error_logs ? 'active' }}">
<button role="tab" class="tab-control {{ has_error_logs ? 'active' }}">
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This template puts an input inside a button, which is invalid HTML markup (and inaccessible one). You cannot have it being both a radio group and an ARIA tablist AFAICT.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm going to fix it in a separate PR. Thanks.

Update: here's the PR: #48963

<input {{ has_error_logs ? 'checked' }} type="radio" id="filter-log-type-error" name="filter-log-type" value="error">
<label for="filter-log-type-error">
Errors
<span class="badge status-{{ collector.counterrors ? 'error' }}">{{ collector.counterrors|default(0) }}</span>
</label>
</li>
</button>

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

<details id="log-filter-priority" class="log-filter">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -663,23 +663,31 @@ if (typeof Sfjs === 'undefined' || typeof Sfjs.loadToolbar === 'undefined') {
},

createTabs: function() {
/* 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');
tabNavigationItem.classList.add('tab-control');
tabNavigationItem.setAttribute('data-tab-id', tabId);
tabNavigationItem.setAttribute('role', 'tab');
javiereguiluz marked this conversation as resolved.
Show resolved Hide resolved
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);

Expand All @@ -693,24 +701,31 @@ if (typeof Sfjs === 'undefined' || typeof Sfjs.loadToolbar === 'undefined') {

/* 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';
const 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 '<li>' element */
while (activeTab.tagName.toLowerCase() !== 'li') {
/* on any of those elements instead of their parent '<button>' element */
while (activeTab.tagName.toLowerCase() !== 'button') {
activeTab = activeTab.parentNode;
}

Expand All @@ -720,9 +735,13 @@ if (typeof Sfjs === 'undefined' || typeof Sfjs.loadToolbar === 'undefined') {
var tabId = tabNavigation[k].getAttribute('data-tab-id');
document.getElementById(tabId).className = 'hidden';
removeClass(tabNavigation[k], 'active');
tabNavigation[k].removeAttribute('aria-selected');
tabNavigation[k].setAttribute('tabindex', '-1');
}

addClass(activeTab, 'active');
activeTab.setAttribute('aria-selected', 'true');
activeTab.removeAttribute('tabindex');
var activeTabId = activeTab.getAttribute('data-tab-id');
document.getElementById(activeTabId).className = 'block';
});
Expand Down Expand Up @@ -894,7 +913,7 @@ if (typeof Sfjs === 'undefined' || typeof Sfjs.loadToolbar === 'undefined') {
document.querySelector('#log-filter-channel .filter-active-num').innerText = (channels.length === selectedChannels.length) ? 'All' : selectedChannels.length;

/* update the currently selected "log type" tab */
document.querySelectorAll('#log-filter-type li').forEach((tab) => tab.classList.remove('active'));
document.querySelectorAll('#log-filter-type .tab-control').forEach((tab) => tab.classList.remove('active'));
document.querySelector(`#log-filter-type input[value="${selectedType}"]`).parentElement.classList.add('active');
},
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -516,7 +516,6 @@ input[type="radio"], input[type="checkbox"] {
color: var(--color-link);
text-decoration: none;
background-color: transparent;
outline: none;
border: 0;
padding: 0;
cursor: pointer;
Expand Down Expand Up @@ -1546,23 +1545,26 @@ tr.status-warning td {
box-shadow: inset 0 0 0 1px var(--tab-border-color), 0 0 0 4px var(--page-background);
margin: 0 0 10px;
}
.tab-navigation li {
.tab-navigation .tab-control {
background: transparent;
border: 0;
box-shadow: none;
transition: box-shadow .05s ease-in, background-color .05s ease-in;
cursor: pointer;
font-size: 14px;
font-weight: 500;
list-style: none;
line-height: 1.4;
margin: 0;
padding: 4px 14px;
position: relative;
text-align: center;
z-index: 1;
}
.sf-tabs-sm .tab-navigation li {
.sf-tabs-sm .tab-navigation .tab-control {
font-size: 13px;
padding: 2.5px 10px;
}
.tab-navigation li:before {
.tab-navigation .tab-control:before {
background: var(--tab-border-color);
bottom: 15%;
content: "";
Expand All @@ -1571,10 +1573,12 @@ tr.status-warning td {
top: 15%;
width: 1px;
}
.tab-navigation li:first-child:before, .tab-navigation li.active + li:before, .tab-navigation li.active:before {
.tab-navigation .tab-control:first-child:before,
.tab-navigation .tab-control.active + .tab-control:before,
.tab-navigation .tab-control.active:before {
width: 0;
}
.tab-navigation li .badge {
.tab-navigation .tab-control .badge {
background: var(--selected-badge-background);
box-shadow: var(--selected-badge-shadow);
color: var(--selected-badge-color);
Expand All @@ -1588,29 +1592,29 @@ tr.status-warning td {
text-align: center;
white-space: nowrap;
}
.tab-navigation li.disabled {
.tab-navigation .tab-control.disabled {
color: var(--tab-disabled-color);
}
.tab-navigation li.active {
.tab-navigation .tab-control.active {
background-color: var(--tab-active-background);
border-radius: 6px;
box-shadow: inset 0 0 0 1.5px var(--tab-active-border-color);
color: var(--tab-active-color);
position: relative;
z-index: 1;
}
.theme-dark .tab-navigation li.active {
.theme-dark .tab-navigation .tab-control.active {
box-shadow: inset 0 0 0 1px var(--tab-border-color);
}
.tab-content > *:first-child {
margin-top: 0;
}
.tab-navigation li .badge.status-warning {
.tab-navigation .tab-control .badge.status-warning {
background: var(--selected-badge-warning-background);
box-shadow: var(--selected-badge-warning-shadow);
color: var(--selected-badge-warning-color);
}
.tab-navigation li .badge.status-error {
.tab-navigation .tab-control .badge.status-error {
background: var(--selected-badge-danger-background);
box-shadow: var(--selected-badge-danger-shadow);
color: var(--selected-badge-danger-color);
Expand Down Expand Up @@ -1784,10 +1788,10 @@ tr.status-warning td {
font-weight: bold;
padding: 0 1px;
}
.log-filter .tab-navigation li input {
.log-filter .tab-navigation .tab-control input {
display: none;
}
.log-filter .tab-navigation li label {
.log-filter .tab-navigation .tab-control label {
cursor: pointer;
}
.log-filters .log-filter .log-filter-content {
Expand Down