Skip to content

Commit 3356f32

Browse files
authored
fix(UI): use role="tabpanel" for control panel sections (#2139)
1 parent 5bb0b76 commit 3356f32

File tree

7 files changed

+89
-60
lines changed

7 files changed

+89
-60
lines changed

src/action/backup.css

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,38 @@
1-
#backup details {
1+
#backup-panel details {
22
padding: 1ch;
33
}
44

5-
#backup details > .content {
5+
#backup-panel details > .content {
66
margin-top: 0.5em;
77

88
display: flex;
99
flex-direction: column;
1010
gap: 0.5em;
1111
}
1212

13-
#backup details[open] ~ details summary ~ * {
13+
#backup-panel details[open] ~ details summary ~ * {
1414
display: none;
1515
}
1616

17-
#backup h4 {
17+
#backup-panel h4 {
1818
display: inline-block;
1919
margin: 0;
2020
}
2121

22-
#backup label {
22+
#backup-panel label {
2323
margin: 0;
2424
}
2525

26-
#backup pre {
26+
#backup-panel pre {
2727
width: 0;
2828
min-width: 100%;
2929

3030
-webkit-user-select: all;
3131
user-select: all;
3232
}
3333

34-
#backup pre,
35-
#backup textarea {
34+
#backup-panel pre,
35+
#backup-panel textarea {
3636
max-height: calc(10em + 2ch);
3737
overflow: auto;
3838
overflow-wrap: break-word;

src/action/links.css

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,32 @@
1-
#links {
2-
position: relative;
3-
4-
margin: 1em 0;
5-
padding: 0 1em;
1+
#links-panel {
2+
padding: 8px;
63
}
74

8-
#links h4 {
9-
margin-bottom: 0;
5+
#links-panel h4 {
6+
margin-block: 8px;
107
}
118

12-
#links ul {
13-
padding-left: 1em;
9+
#links-panel ul {
10+
padding-inline: 16px;
11+
margin-block-start: 0;
12+
margin-block-end: 16px;
1413
}
1514

16-
#links h4 + ul {
17-
margin-top: 1ch;
15+
#links-panel ul:last-child {
16+
margin-block-end: 8px;
1817
}
1918

20-
#links li {
21-
margin-bottom: 1ch;
19+
#links-panel ul li {
20+
margin-bottom: 8px;
2221
}
2322

24-
#links a {
23+
#links-panel a {
2524
font-weight: bold;
2625
text-decoration: none;
2726
}
2827

29-
#links :link,
30-
#links :visited {
28+
#links-panel :link,
29+
#links-panel :visited {
3130
color: rgb(var(--accent));
3231
}
3332

src/action/popup.css

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ body {
7272
display: none;
7373
}
7474

75-
nav {
75+
[role="tablist"] {
7676
display: flex;
7777
flex-direction: row;
7878
justify-content: center;
@@ -81,43 +81,49 @@ nav {
8181
border-bottom: 1px solid rgb(var(--active-grey));
8282
}
8383

84-
nav a {
84+
[role="tablist"] [role="tab"] {
8585
flex-grow: 1;
8686
padding: 8px;
87+
border: none;
8788
border-radius: 5px;
8889
margin: 0 4px;
8990

91+
background-color: transparent;
9092
color: rgb(var(--black));
9193
font-weight: bold;
9294
text-align: center;
9395
text-decoration: none;
9496
}
9597

96-
nav a:hover {
98+
[role="tablist"] [role="tab"]:hover {
9799
background-color: rgb(var(--passive-grey));
100+
cursor: pointer;
98101
}
99102

100-
nav a:active, nav a.selected {
103+
[role="tablist"] [role="tab"]:active,
104+
[role="tablist"] [role="tab"][aria-selected="true"] {
101105
background-color: rgb(var(--active-grey));
102106
}
103107

104-
section:not(.open) {
105-
display: none;
108+
[role="tabpanel"] {
109+
position: relative;
106110
}
107111

108-
section.open:empty {
109-
display: flex;
110-
justify-content: center;
111-
align-items: center;
112-
margin: 1em 0;
112+
[role="tabpanel"]:focus-visible {
113+
outline-offset: -3px;
113114
}
114115

115-
section.open:empty::before {
116-
content: "No one’s around to help.";
117-
}
116+
[role="tabpanel"]:focus-visible::after {
117+
position: absolute;
118+
top: 0;
119+
left: 0;
120+
right: 0;
121+
bottom: 0;
122+
z-index: 1;
118123

119-
section h2 {
120-
text-align: center;
124+
content: "";
125+
outline: inherit;
126+
outline-offset: inherit;
121127
}
122128

123129
input[type="text"],

src/action/popup.html

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,12 @@
2828
ℹ️ XKit Rewritten can also be configured via the button in the browser toolbar.
2929
</header>
3030
<main>
31-
<nav>
32-
<a href="#configuration" role="button" class="selected">Configuration</a>
33-
<a href="#backup" role="button">Backup</a>
34-
<a href="#links" role="button">Links</a>
35-
</nav>
36-
<section id="configuration" class="open">
31+
<div role="tablist" aria-label="Navigation">
32+
<button id="configuration-tab" role="tab" aria-controls="configuration-panel" aria-selected="true" tabindex="0">Configuration</button>
33+
<button id="backup-tab" role="tab" aria-controls="backup-panel" aria-selected="false" tabindex="-1">Backup</button>
34+
<button id="links-tab" role="tab" aria-controls="links-panel" aria-selected="false" tabindex="-1">Links</button>
35+
</div>
36+
<section id="configuration-panel" role="tabpanel" aria-labelledby="configuration-tab" tabindex="0">
3737
<div class="finder">
3838
<input id="search" type="text" placeholder="Search" autocomplete="off" spellcheck="false">
3939
<label for="filter">Filter by</label>
@@ -48,7 +48,7 @@
4848
</div>
4949
<div class="features"></div>
5050
</section>
51-
<section id="backup">
51+
<section id="backup-panel" role="tabpanel" aria-labelledby="backup-tab" tabindex="0" hidden>
5252
<details id="export" open>
5353
<summary><h4>Export</h4></summary>
5454
<div class="content">
@@ -69,7 +69,7 @@
6969
</div>
7070
</details>
7171
</section>
72-
<section id="links">
72+
<section id="links-panel" role="tabpanel" aria-labelledby="links-tab" tabindex="0" hidden>
7373
<h4>Help & information</h4>
7474
<ul>
7575
<li><a href="https://github.com/AprilSylph/XKit-Rewritten/wiki" target="_blank">User guide</a></li>

src/action/popup.js

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,40 @@ const checkForNoResults = function () {
88
document.querySelector('.no-results').style.display = nothingFound ? 'flex' : 'none';
99
};
1010

11-
$('nav a').on('click', event => {
12-
event.preventDefault();
11+
document.querySelector('[role="tablist"]').addEventListener('keydown', (/** @type {KeyboardEvent} */ event) => {
12+
if (event.target.getAttribute('role') !== 'tab') return;
1313

14-
$('nav .selected').removeClass('selected');
15-
$(event.currentTarget).addClass('selected');
14+
switch (event.key) {
15+
case 'ArrowLeft':
16+
event.target.previousElementSibling?.focus();
17+
event.target.previousElementSibling?.click();
18+
break;
19+
case 'ArrowRight':
20+
event.target.nextElementSibling?.focus();
21+
event.target.nextElementSibling?.click();
22+
break;
23+
default:
24+
return;
25+
}
1626

17-
$('section.open').removeClass('open');
18-
$(`section${event.currentTarget.getAttribute('href')}`).addClass('open');
27+
event.stopPropagation();
1928
});
2029

30+
[...document.querySelectorAll('[role="tab"]')].forEach(tab =>
31+
tab.addEventListener('click', ({ currentTarget }) => {
32+
const targetPanelId = currentTarget.getAttribute('aria-controls');
33+
const tabList = currentTarget.closest('[role="tablist"]');
34+
const tabListChildren = Array.from(tabList.children);
35+
const tabListPanelIds = tabListChildren.map(tab => tab.getAttribute('aria-controls'));
36+
37+
tabListChildren.forEach(tab => {
38+
tab.setAttribute('aria-selected', tab === currentTarget ? 'true' : 'false');
39+
tab.setAttribute('tabindex', tab === currentTarget ? '0' : '-1');
40+
});
41+
tabListPanelIds.forEach(panelId => document.getElementById(panelId)?.toggleAttribute('hidden', targetPanelId !== panelId));
42+
}),
43+
);
44+
2145
document.getElementById('search').addEventListener('input', ({ currentTarget }) => {
2246
const query = currentTarget.value.toLowerCase();
2347
const featureElements = [...document.querySelectorAll('xkit-feature')];

src/action/render_backup.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ const localRestore = async function () {
6969
localRestoreButton.classList.add('success');
7070
localRestoreButton.textContent = 'Successfully restored!';
7171
localImportTextarea.value = '';
72-
document.querySelector('a[href="#configuration"]').classList.add('outdated');
72+
document.getElementById('configuration-tab').classList.add('outdated');
7373
} catch (exception) {
7474
localRestoreButton.classList.add('failure');
7575
localRestoreButton.textContent =
@@ -96,7 +96,7 @@ const renderLocalBackup = async function () {
9696

9797
renderLocalBackup();
9898

99-
document.querySelectorAll('#backup details').forEach(details => details.addEventListener('toggle', ({ currentTarget }) => {
99+
document.querySelectorAll('#backup-panel details').forEach(details => details.addEventListener('toggle', ({ currentTarget }) => {
100100
if (currentTarget.open) {
101101
[...currentTarget.parentNode.children]
102102
.filter(element => element !== currentTarget)

src/action/render_features.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ import { TextPreference } from './components/text-preference/index.js';
66
import { TextAreaPreference } from './components/textarea-preference/index.js';
77
import { XKitFeature } from './components/xkit-feature/index.js';
88

9-
const configSection = document.getElementById('configuration');
10-
const configSectionLink = document.querySelector('a[href="#configuration"]');
11-
const featuresDiv = configSection.querySelector('.features');
9+
const configPanel = document.getElementById('configuration-panel');
10+
const configTab = document.getElementById('configuration-tab');
11+
const featuresDiv = configPanel.querySelector('.features');
1212

1313
const enabledFeaturesKey = 'enabledScripts';
1414
const specialAccessKey = 'specialAccess';
@@ -146,7 +146,7 @@ const renderFeatures = async function () {
146146

147147
renderFeatures();
148148

149-
configSectionLink.addEventListener('click', ({ currentTarget }) => {
149+
configTab.addEventListener('click', ({ currentTarget }) => {
150150
if (currentTarget.classList.contains('outdated')) {
151151
currentTarget.classList.remove('outdated');
152152
renderFeatures();

0 commit comments

Comments
 (0)