feat(a11y): add role=img and sr-only data to map and chart components

Add ARIA role=img with descriptive labels to world-map SVG and
donut-chart SVG. Include a screen-reader-only data table in world-map
for country/count pairs.
This commit is contained in:
Jon Seager 2026-02-09 19:54:42 +00:00
parent 8f79c5aaf3
commit f4411fdc76
No known key found for this signature in database
2 changed files with 26 additions and 1 deletions

View file

@ -103,7 +103,7 @@ class DonutChart extends HTMLElement {
});
this.innerHTML = `<div style="display:flex;flex-direction:column;align-items:center;gap:1rem">
<svg width="${size}" height="${size}" viewBox="0 0 ${size} ${size}" style="display:block">
<svg width="${size}" height="${size}" viewBox="0 0 ${size} ${size}" style="display:block" role="img" aria-label="Distribution: ${items.map((i) => `${esc(i.label)} ${Math.round((i.count / total) * 100)}%`).join(", ")}">
${segments.join("")}
${(() => {
const icon = DONUT_ICONS[this.dataset.icon];

View file

@ -71,6 +71,31 @@ customElements.define(
svg.style.display = "block";
this.appendChild(svg);
svg.setAttribute("role", "img");
svg.setAttribute(
"aria-label",
"World map showing coffee origins by country",
);
const srOnly = this.querySelector(".sr-only");
if (srOnly) srOnly.remove();
const raw = this.dataset.countries || "";
if (raw) {
const entries = raw.split(",").map((e) => e.split(":"));
const sr = document.createElement("div");
sr.className = "sr-only";
sr.innerHTML =
"<table><caption>Coffee origins by country</caption><thead><tr><th>Country</th><th>Count</th></tr></thead><tbody>" +
entries
.map(
([code, count]) =>
`<tr><td>${code.toUpperCase()}</td><td>${count}</td></tr>`,
)
.join("") +
"</tbody></table>";
this.appendChild(sr);
}
this._recolor();
}