fix(ui): improve focus and status accessibility

This commit is contained in:
2026-07-31 22:34:25 -04:00
parent d5c2d0e343
commit e4edf10440
9 changed files with 47 additions and 15 deletions
+1 -1
View File
@@ -13,7 +13,7 @@ Constraints: local commits only; no push; no browser testing; one commit per fea
- [x] Give in-player controls accessible names, keyboard behavior, and visible focus.
- [x] Make control-bar customization operable by keyboard as well as drag and drop.
- [x] Label generated shortcut and site-rule form controls.
- [ ] Improve popup status announcements, focus indicators, and icon-search semantics.
- [x] Improve popup status announcements, focus indicators, and icon-search semantics.
## Settings safety and validation
+11 -4
View File
@@ -7,6 +7,7 @@
--text: #17191c;
--muted: #626b76;
--accent: #111827;
--focus-ring: #2563eb;
--switch-track-off: #c1cad6;
--switch-track-off-border: #aeb8c5;
--switch-track-on: #111827;
@@ -177,9 +178,14 @@ a:visited {
text-underline-offset: 0.14em;
}
a:hover,
a:focus {
color: #000;
a:hover {
color: var(--text);
text-decoration-thickness: 2px;
}
a:focus-visible {
outline: 2px solid var(--focus-ring);
outline-offset: 2px;
}
code {
@@ -225,7 +231,7 @@ input[type="checkbox"]:focus-visible,
input[type="text"]:focus,
select:focus,
textarea:focus {
outline: 2px solid rgba(17, 24, 39, 0.14);
outline: 2px solid var(--focus-ring);
outline-offset: 2px;
}
@@ -1242,6 +1248,7 @@ button.lucide-result-tile.lucide-picked {
--text: #f2f4f6;
--muted: #a0a8b2;
--accent: #f2f4f6;
--focus-ring: #93c5fd;
--switch-track-off: #374151;
--switch-track-off-border: #4b5563;
--switch-track-on: #aab7c6;
+1 -1
View File
@@ -591,7 +591,7 @@
<div
id="lucideIconResults"
class="lucide-icon-results"
role="listbox"
role="group"
aria-label="Matching Lucide icons"
></div>
<p id="lucideIconStatus" class="lucide-icon-status" aria-live="polite"></p>
+8
View File
@@ -1741,6 +1741,10 @@ function initLucideButtonIconsUI() {
b.dataset.slug = slug;
b.title = slug;
b.setAttribute("aria-label", slug);
b.setAttribute(
"aria-pressed",
slug === lucidePickerSelectedSlug ? "true" : "false"
);
if (slug === lucidePickerSelectedSlug) {
b.classList.add("lucide-picked");
}
@@ -1762,6 +1766,10 @@ function initLucideButtonIconsUI() {
resultsEl.querySelectorAll("button"),
function (x) {
x.classList.toggle("lucide-picked", x.dataset.slug === slug);
x.setAttribute(
"aria-pressed",
x.dataset.slug === slug ? "true" : "false"
);
}
);
fetchLucideSvg(slug)
+10 -8
View File
@@ -4,8 +4,9 @@
--border: #e2e5e9;
--border-strong: #d4d9e0;
--text: #17191c;
--muted: #626b76;
--accent: #111827;
--muted: #626b76;
--accent: #111827;
--focus-ring: #2563eb;
}
* {
@@ -83,8 +84,8 @@ button:active {
background: #f1f3f5;
}
button:focus-visible {
outline: 2px solid rgba(17, 24, 39, 0.14);
button:focus-visible {
outline: 2px solid var(--focus-ring);
outline-offset: 2px;
}
@@ -250,8 +251,8 @@ button:focus-visible {
background: #f1f3f5;
}
.donate-icon-btn:focus-visible {
outline: 2px solid rgba(17, 24, 39, 0.14);
.donate-icon-btn:focus-visible {
outline: 2px solid var(--focus-ring);
outline-offset: 2px;
position: relative;
z-index: 1;
@@ -295,8 +296,9 @@ button:focus-visible {
--border: #2b3138;
--border-strong: #3a414a;
--text: #f2f4f6;
--muted: #a0a8b2;
--accent: #f2f4f6;
--muted: #a0a8b2;
--accent: #f2f4f6;
--focus-ring: #93c5fd;
}
body {
+6 -1
View File
@@ -32,7 +32,12 @@
<button id="enable" class="hide">Enable</button>
<button id="disable">Disable</button>
</div>
<div id="status" class="popup-status hide"></div>
<div
id="status"
class="popup-status hide"
role="status"
aria-live="polite"
></div>
<div class="popup-links">
<button id="config">Settings</button>
<div class="popup-secondary">
+1
View File
@@ -247,6 +247,7 @@ document.addEventListener("DOMContentLoaded", function () {
}
if (def.className) btn.className = def.className;
btn.title = btnId.charAt(0).toUpperCase() + btnId.slice(1);
btn.setAttribute("aria-label", btn.title);
btn.addEventListener("click", function () {
if (btnId === "settings") {
+3
View File
@@ -116,6 +116,9 @@ describe("options page", () => {
it("labels shortcut and generated site-rule controls", async () => {
await setupOptions();
expect(document.getElementById("lucideIconResults").getAttribute("role")).toBe(
"group"
);
expect(
document.querySelector('#display .customKey').getAttribute("aria-label")
).toBe("Show/hide controller key");
+6
View File
@@ -35,6 +35,12 @@ describe("popup UI", () => {
expect(
document.querySelectorAll("#popupControlBar button").length
).toBeGreaterThan(0);
expect(document.getElementById("status").getAttribute("role")).toBe(
"status"
);
expect(
document.querySelector("#popupControlBar button").getAttribute("aria-label")
).not.toBe("");
});
it("shows controls when globally disabled but a whitelist site rule matches", async () => {