Did you know that with some simple JavaScript, you can highlight headings, display accessible names, check image alternatives, outline landmarks, and inspect many other accessibility features on any page?
Let’s explore how to open the console and use a few simple scripts to inspect accessibility features on any page.
What is the console?
The console is a tool built into every modern browser. It lets you:
- run small pieces of JavaScript
- inspect information about the page
- quickly test ideas without changing the source code
Think of it as a place to try things out and see how the page behaves. You’re not modifying the real website — just running temporary code in your own browser to inspect or experiment with what’s on the page.
How to open the console
Mac
- Chrome: Option + Command + J
- Firefox: Option + Command + K
- Safari: First enable the Develop menu (Preferences → Advanced → “Show Develop menu”). Then press Option + Command + C.
Windows
- Chrome / Edge: Ctrl + Shift + J
- Firefox: Ctrl + Shift + K
How to use these scripts
Each example script in this article follows the same simple process. You don’t need to install anything, and you can’t break the website — these scripts only display information visually or in the console.
- Open the browser console
- Paste the script
- Press ENTER
- View the results
- Refresh the page to clear the overlays and return to normal.
Some quick examples
Here’s a simple script you can try first. It shows every link on the page as a NodeList in the console, which is useful for quick checks.
document.querySelectorAll("a");
Or you could highlight all links on the page:
document.querySelectorAll("a").forEach(a => a.style.outline = "2px solid red");
Some people turn snippets like these into bookmarklets (small saved JavaScript actions). That can be useful, but for teaching and quick testing, the console is often easier. I explain why at the end of the article.
Some read-to-use examples
The following examples are more advanced, but all use the same basic idea: outline elements and place badges using simple DOM queries. You don’t need to understand or memorise every line — just paste them in and explore the results. Feel free to adapt or optimise them as needed.
To test these scripts on the same pages shown in the videos, try these:
1. Display all headings:
View the script
// ----------------------
// Scroll-Safe Overlay Container
// ----------------------
const overlay = document.createElement("div");
overlay.style.position = "absolute";
overlay.style.top = "0";
overlay.style.left = "0";
overlay.style.width = "100%";
overlay.style.pointerEvents = "none";
overlay.style.zIndex = "999999";
document.body.appendChild(overlay);
// ----------------------
// Colour map per heading level
// ----------------------
const colours = {
H1: "red",
H2: "green",
H3: "blue",
H4: "purple",
H5: "deepPink",
H6: "black"
};
// ----------------------
// Main Logic
// ----------------------
document.querySelectorAll("h1, h2, h3, h4, h5, h6").forEach(h => {
const tag = h.tagName.toUpperCase();
const colour = colours[tag] || "#147580"; // fallback just in case
// Border
h.style.outline = `3px solid ${colour}`;
// Position
const rect = h.getBoundingClientRect();
const left = rect.left + window.scrollX;
const top = rect.top + window.scrollY;
// Floating badge
const badge = document.createElement("div");
badge.textContent = tag;
badge.style.position = "absolute";
badge.style.left = `${left - 20}px`;
badge.style.top = `${top - 30}px`;
badge.style.background = colour;
badge.style.color = "white";
badge.style.padding = "5px 8px";
badge.style.borderRadius = "5px";
badge.style.fontSize = "16px";
badge.style.whiteSpace = "nowrap";
badge.style.pointerEvents = "none";
badge.style.zIndex = "999999";
overlay.appendChild(badge);
});
2. Display all buttons:
View the script
// ----------------------
// Scroll-safe overlay container
// ----------------------
const overlay = document.createElement("div");
overlay.style.position = "absolute";
overlay.style.top = "0";
overlay.style.left = "0";
overlay.style.width = "100%";
overlay.style.pointerEvents = "none";
overlay.style.zIndex = "999999";
document.body.appendChild(overlay);
// ----------------------
// Helper: Compute accessible name
// ----------------------
function getAccessibleName(el) {
// aria-label
const ariaLabel = el.getAttribute("aria-label");
if (ariaLabel && ariaLabel.trim()) return ariaLabel.trim();
// aria-labelledby
const labelledby = el.getAttribute("aria-labelledby");
if (labelledby) {
const ids = labelledby.trim().split(/\s+/);
const texts = ids.map(id => {
const ref = document.getElementById(id);
return ref ? ref.textContent.trim() : "";
}).filter(Boolean);
if (texts.length) return texts.join(" ");
}
// value for input buttons
if (el.tagName === "INPUT") {
const value = el.getAttribute("value");
if (value && value.trim()) return value.trim();
}
// visible text
const txt = el.textContent.trim();
if (txt) return txt;
return "(no name)";
}
// ----------------------
// Button selector
// ----------------------
const buttonSelector = `
button,
[role="button"],
input[type="button"],
input[type="submit"],
input[type="reset"]
`;
const buttons = Array.from(document.querySelectorAll(buttonSelector));
// ----------------------
// Process each button
// ----------------------
buttons.forEach(btn => {
const name = getAccessibleName(btn);
// Add outline
btn.style.outline = "3px solid #ca6510";
// Compute location
const rect = btn.getBoundingClientRect();
const left = rect.left + window.scrollX;
const top = rect.top + window.scrollY;
// Floating badge
const badge = document.createElement("div");
badge.textContent = `Button: ${name}`;
badge.style.position = "absolute";
badge.style.left = `${left}px`;
badge.style.top = `${top - 28}px`;
badge.style.background = "#ca6510";
badge.style.color = "white";
badge.style.padding = "5px";
badge.style.fontSize = "16px";
badge.style.borderRadius = "5px";
badge.style.whiteSpace = "nowrap";
badge.style.pointerEvents = "none";
badge.style.zIndex = "999999";
overlay.appendChild(badge);
});
3. Display image alternatives:
View the script
// ----------------------
// Scroll-Safe Overlay Container
// ----------------------
const overlay = document.createElement("div");
overlay.style.position = "absolute";
overlay.style.top = "0";
overlay.style.left = "0";
overlay.style.width = "100%";
overlay.style.pointerEvents = "none";
overlay.style.zIndex = "999999";
document.body.appendChild(overlay);
// ----------------------
// Main Logic
// ----------------------
document.querySelectorAll("img").forEach(img => {
// Determine alt text
const alt = img.getAttribute("alt");
const altText = (alt && alt.trim()) ? alt.trim() : "(missing alt)";
// Add visible outline
img.style.outline = "2px solid #b23a48";
// Get absolute coordinates
const rect = img.getBoundingClientRect();
const left = rect.left + window.scrollX;
const top = rect.top + window.scrollY;
// Create floating badge
const badge = document.createElement("div");
badge.textContent = altText;
badge.style.position = "absolute";
badge.style.left = `${left -20}px`;
badge.style.top = `${top - 30}px`;
badge.style.background = "#b23a48";
badge.style.color = "white";
badge.style.padding = "5px";
badge.style.borderRadius = "5px";
badge.style.fontSize = "16px";
badge.style.whiteSpace = "nowrap";
badge.style.pointerEvents = "none";
// Add to overlay layer
overlay.appendChild(badge);
});
4. Display all links:
View the script
// ----------------------
// Accessible Name Helper
// ----------------------
function getLinkName(el) {
// 1. aria-labelledby
const labelledby = el.getAttribute("aria-labelledby");
if (labelledby) {
const parts = labelledby.split(/\s+/).map(id => {
const ref = document.getElementById(id);
return ref ? ref.textContent.trim() : "";
});
const name = parts.join(" ").trim();
if (name) return name;
}
// 2. aria-label
const ariaLabel = el.getAttribute("aria-label");
if (ariaLabel && ariaLabel.trim()) return ariaLabel.trim();
// 3. Text content
const text = el.textContent.trim();
if (text) return text;
// 4. Images inside links (alt text)
const img = el.querySelector("img");
if (img) {
const alt = img.getAttribute("alt");
if (alt && alt.trim()) return alt.trim();
}
return "(no accessible name)";
}
// ----------------------
// Scroll-Safe Overlay Container
// ----------------------
const overlay = document.createElement("div");
overlay.style.position = "absolute";
overlay.style.top = "0";
overlay.style.left = "0";
overlay.style.width = "100%";
overlay.style.pointerEvents = "none";
overlay.style.zIndex = "999999";
document.body.appendChild(overlay);
// ----------------------
// Main Logic
// ----------------------
document.querySelectorAll("a").forEach(a => {
const accName = getLinkName(a);
// Add border to the link
a.style.outline = "2px solid #6a1b9a";
// Get page coordinates
const rect = a.getBoundingClientRect();
const left = rect.left + window.scrollX;
const top = rect.top + window.scrollY;
// Create floating label
const badge = document.createElement("div");
badge.textContent = accName;
badge.style.position = "absolute";
badge.style.left = `${left}px`;
badge.style.top = `${top - 28}px`;
badge.style.background = "#6a1b9a";
badge.style.color = "white";
badge.style.padding = "4px 6px";
badge.style.borderRadius = "4px";
badge.style.fontSize = "16px";
badge.style.whiteSpace = "nowrap";
badge.style.pointerEvents = "none";
overlay.appendChild(badge);
});
5. Display all lists and list items:
View the script
// -------------------------------------------
// Scroll-safe overlay container
// -------------------------------------------
const overlay = document.createElement("div");
overlay.style.position = "absolute";
overlay.style.top = "0";
overlay.style.left = "0";
overlay.style.width = "100%";
overlay.style.pointerEvents = "none";
overlay.style.zIndex = "999999";
document.body.appendChild(overlay);
// -------------------------------------------
// Badge helper
// -------------------------------------------
function drawBadge(el, label, color) {
// Outline element
el.style.outline = `3px solid ${color}`;
// Position calculation with scroll offsets
const rect = el.getBoundingClientRect();
const left = rect.left + window.scrollX;
const top = rect.top + window.scrollY - 28; // float above element
// Create floating badge
const badge = document.createElement("div");
badge.textContent = label;
badge.style.position = "absolute";
badge.style.left = `${left}px`;
badge.style.top = `${top}px`;
badge.style.background = color;
badge.style.color = "white";
badge.style.padding = "5px";
badge.style.borderRadius = "5px";
badge.style.fontSize = "16px";
badge.style.whiteSpace = "nowrap";
badge.style.pointerEvents = "none";
badge.style.zIndex = "999999";
overlay.appendChild(badge);
}
// -------------------------------------------
// 1. Highlight UL / OL / DL
// -------------------------------------------
document.querySelectorAll("ul").forEach(el => {
drawBadge(el, "UL", "#006d77");
});
document.querySelectorAll("ol").forEach(el => {
drawBadge(el, "OL", "#005f8f");
});
document.querySelectorAll("dl").forEach(el => {
drawBadge(el, "DL", "#4a148c");
});
// -------------------------------------------
// 2. Highlight LI / DT / DD
// -------------------------------------------
document.querySelectorAll("li").forEach(el => {
drawBadge(el, "LI", "#8a5a44");
});
document.querySelectorAll("dt").forEach(el => {
drawBadge(el, "DT", "#7f3d9c");
});
document.querySelectorAll("dd").forEach(el => {
drawBadge(el, "DD", "#b83b5e");
});
6. Display table captions and table headers:
View the script
/* -----------------------------------------
Shared overlay container (scroll-safe)
------------------------------------------ */
const overlay = document.createElement("div");
overlay.style.position = "absolute";
overlay.style.top = "0";
overlay.style.left = "0";
overlay.style.width = "100%";
overlay.style.pointerEvents = "none";
overlay.style.zIndex = "999999";
document.body.appendChild(overlay);
/* -----------------------------------------
1. Highlight all TABLES
------------------------------------------ */
document.querySelectorAll("table").forEach(table => {
// Add visible outline
table.style.outline = "3px solid #d35400";
// Get caption text (if present)
const captionEl = table.querySelector("caption");
const caption = captionEl && captionEl.textContent.trim()
? captionEl.textContent.trim()
: "(no caption)";
// Compute position
const rect = table.getBoundingClientRect();
const left = rect.left + window.scrollX;
const top = rect.top + window.scrollY;
// Floating label for the table
const badge = document.createElement("div");
badge.textContent = `Table: ${caption}`;
badge.style.position = "absolute";
badge.style.left = `${left}px`;
badge.style.top = `${top - 30}px`;
badge.style.background = "#d35400";
badge.style.color = "white";
badge.style.padding = "4px 6px";
badge.style.borderRadius = "4px";
badge.style.fontSize = "14px";
badge.style.whiteSpace = "nowrap";
badge.style.pointerEvents = "none";
overlay.appendChild(badge);
});
/* -----------------------------------------
2. Highlight all TH cells
------------------------------------------ */
document.querySelectorAll("th").forEach(th => {
// Add outline
th.style.outline = "2px dashed #8e44ad";
// Compute position
const rect = th.getBoundingClientRect();
const left = rect.left + window.scrollX;
const top = rect.top + window.scrollY;
// Floating label
const thBadge = document.createElement("div");
thBadge.textContent = "TH";
thBadge.style.position = "absolute";
thBadge.style.left = `${left}px`;
thBadge.style.top = `${top - 20}px`;
thBadge.style.background = "#8e44ad";
thBadge.style.color = "white";
thBadge.style.padding = "2px 4px";
thBadge.style.borderRadius = "3px";
thBadge.style.fontSize = "16px";
thBadge.style.whiteSpace = "nowrap";
thBadge.style.pointerEvents = "none";
overlay.appendChild(thBadge);
});
7. Display landmark roles and their names:
View the script
// ----------------------
// Scroll-safe overlay container
// ----------------------
const overlay = document.createElement("div");
overlay.style.position = "absolute";
overlay.style.top = "0";
overlay.style.left = "0";
overlay.style.width = "100%";
overlay.style.pointerEvents = "none";
overlay.style.zIndex = "999999";
document.body.appendChild(overlay);
// ----------------------
// Landmark roles + colours
// ----------------------
const landmarkRoles = [
"banner",
"navigation",
"main",
"contentinfo",
"complementary",
"search",
"region",
];
const roleColors = {
banner: "#0a6ebd",
navigation: "#b85c00",
main: "#006400",
contentinfo: "#7a0099",
complementary: "#990000",
search: "#357a38",
region: "#666600"
};
/* Native HTML elements that map to landmarks:
header, nav, main, footer, aside, section (if named), article (if named)
*/
const selectors = [
"header",
"nav",
"main",
"footer",
"aside",
"section",
"article",
"[role]"
].join(",");
// ----------------------
// Helper: compute landmark role
// ----------------------
function getLandmarkRole(el) {
const role = el.getAttribute("role");
if (landmarkRoles.includes(role)) return role;
const tag = el.tagName.toLowerCase();
if (tag === "header") return "banner";
if (tag === "nav") return "navigation";
if (tag === "main") return "main";
if (tag === "footer") return "contentinfo";
if (tag === "aside") return "complementary";
if ((tag === "section" || tag === "article") &&
(el.hasAttribute("aria-label") || el.hasAttribute("aria-labelledby"))) {
return "region";
}
return null;
}
// ----------------------
// Helper: compute accessible name
// ----------------------
function getAccessibleName(el) {
const ariaLabel = el.getAttribute("aria-label");
if (ariaLabel && ariaLabel.trim()) return ariaLabel.trim();
const labelledby = el.getAttribute("aria-labelledby");
if (labelledby) {
const ids = labelledby.split(" ");
const texts = ids.map(id => {
const ref = document.getElementById(id);
return ref ? ref.textContent.trim() : "";
}).filter(Boolean);
if (texts.length) return texts.join(" ");
}
return "(no name)";
}
// ----------------------
// Main logic
// ----------------------
document.querySelectorAll(selectors).forEach(el => {
const role = getLandmarkRole(el);
if (!role) return;
// Apply outline using role colour
const color = roleColors[role] || "#0a6ebd";
el.style.outline = `3px solid ${color}`;
const rect = el.getBoundingClientRect();
const left = rect.left + window.scrollX;
const top = rect.top + window.scrollY;
const accName = getAccessibleName(el);
const badge = document.createElement("div");
badge.textContent = accName !== "(no name)" ? `${role}: ${accName}` : role;
badge.style.position = "absolute";
badge.style.left = `${left}px`;
badge.style.top = `${top - 30}px`;
badge.style.background = color;
badge.style.color = "white";
badge.style.padding = "5px";
badge.style.borderRadius = "5px";
badge.style.fontSize = "16px";
badge.style.whiteSpace = "nowrap";
badge.style.pointerEvents = "none";
badge.style.zIndex = "999999";
overlay.appendChild(badge);
});
8. Display form labels:
View the script
function getAccName(el) {
// 1. aria-labelledby
const labelledby = el.getAttribute("aria-labelledby");
if (labelledby) {
const parts = labelledby.split(/\s+/).map(id => {
const ref = document.getElementById(id);
return ref ? ref.textContent.trim() : "";
});
const name = parts.join(" ").trim();
if (name) return name;
}
// 2. aria-label
const ariaLabel = el.getAttribute("aria-label");
if (ariaLabel && ariaLabel.trim()) return ariaLabel.trim();
// 3. label[for]
if (el.id) {
const explicit = document.querySelector(`label[for="${el.id}"]`);
if (explicit) {
const name = explicit.textContent.trim();
if (name) return name;
}
}
// 4. nested label
const nestedLabel = el.closest("label");
if (nestedLabel) {
const name = nestedLabel.textContent.trim();
if (name) return name;
}
// 5. element text content
const text = el.textContent.trim();
if (text) return text;
// 6. placeholder fallback
const placeholder = el.getAttribute("placeholder");
if (placeholder && placeholder.trim()) return placeholder.trim();
return "(no accessible name)";
}
// -------------------------------------------
// SCROLL-SAFE OVERLAY (absolute, not fixed)
// -------------------------------------------
const overlay = document.createElement("div");
overlay.style.position = "absolute";
overlay.style.top = "0";
overlay.style.left = "0";
overlay.style.width = "100%";
overlay.style.pointerEvents = "none";
overlay.style.zIndex = "999999";
document.body.appendChild(overlay);
// -------------------------------------------
// Elements to inspect
// -------------------------------------------
const controls = document.querySelectorAll(
'input, select, textarea, [role="textbox"], [role="combobox"], [role="spinbutton"]'
);
// -------------------------------------------
// Main rendering logic
// -------------------------------------------
controls.forEach(ctrl => {
const accName = getAccName(ctrl);
// Outline the control
ctrl.style.outline = "2px solid #0a558c";
// Compute absolute coordinates
const rect = ctrl.getBoundingClientRect();
const left = rect.left + window.scrollX - 20;
const top = rect.top + window.scrollY - 30;
// Create floating badge
const badge = document.createElement("div");
badge.textContent = accName;
badge.style.position = "absolute";
badge.style.left = `${left}px`;
badge.style.top = `${top}px`;
badge.style.background = "#0a558c";
badge.style.color = "white";
badge.style.padding = "5px";
badge.style.borderRadius = "5px";
badge.style.fontSize = "16px";
badge.style.whiteSpace = "nowrap";
badge.style.pointerEvents = "none";
overlay.appendChild(badge);
});
9. Display form field descriptions:
View the script
/* -----------------------------------------
Shared overlay container (scroll-safe)
------------------------------------------ */
const overlay = document.createElement("div");
overlay.style.position = "absolute";
overlay.style.top = "0";
overlay.style.left = "0";
overlay.style.width = "100%";
overlay.style.pointerEvents = "none";
overlay.style.zIndex = "999999";
document.body.appendChild(overlay);
/* -----------------------------------------
Find all elements with aria-describedby
------------------------------------------ */
document.querySelectorAll("[aria-describedby]").forEach(el => {
const idList = el.getAttribute("aria-describedby")
.trim()
.split(/\s+/);
// Compute description text from referenced elements
const description = idList
.map(id => {
const ref = document.getElementById(id);
return ref ? ref.textContent.trim() : `(missing element #${id})`;
})
.filter(Boolean)
.join(" ");
// Add visible outline
el.style.outline = "3px solid #0d6efd";
// Compute absolute element position
const rect = el.getBoundingClientRect();
const left = rect.left + window.scrollX;
const top = rect.top + window.scrollY;
// Create floating badge
const badge = document.createElement("div");
badge.textContent = `Description: ${description}`;
badge.style.position = "absolute";
badge.style.left = `${left -10}px`;
badge.style.top = `${top - 30}px`;
badge.style.background = "#0d6efd";
badge.style.color = "white";
badge.style.padding = "5px";
badge.style.borderRadius = "5px";
badge.style.fontSize = "16px";
badge.style.whiteSpace = "nowrap";
badge.style.pointerEvents = "none";
overlay.appendChild(badge);
});
10. Display fieldsets and captions:
View the script
// ----------------------
// Scroll-safe overlay container
// ----------------------
const overlay = document.createElement("div");
overlay.style.position = "absolute";
overlay.style.top = "0";
overlay.style.left = "0";
overlay.style.width = "100%";
overlay.style.pointerEvents = "none";
overlay.style.zIndex = "999999";
document.body.appendChild(overlay);
// ----------------------
// Helpers
// ----------------------
// Accessible name helper (shared with radio-group)
function getAccessibleName(el) {
// 1. aria-label
const ariaLabel = el.getAttribute("aria-label");
if (ariaLabel && ariaLabel.trim()) return ariaLabel.trim();
// 2. aria-labelledby
const labelledby = el.getAttribute("aria-labelledby");
if (labelledby) {
const ids = labelledby.split(" ");
const texts = ids.map(id => {
const ref = document.getElementById(id);
return ref ? ref.textContent.trim() : "";
}).filter(Boolean);
if (texts.length) return texts.join(" ");
}
return "(no name)";
}
// ----------------------
// 1. FIELDSETS
// ----------------------
document.querySelectorAll("fieldset").forEach(fs => {
// Compute accessible name from LEGEND
const legend = fs.querySelector("legend");
const name = legend && legend.textContent.trim()
? legend.textContent.trim()
: "(no name)";
// Outline fieldset
fs.style.outline = "3px solid #1e8449";
// Position of fieldset
const rect = fs.getBoundingClientRect();
const left = rect.left + window.scrollX;
const top = rect.top + window.scrollY;
// Floating badge
const badge = document.createElement("div");
badge.textContent = `Fieldset: ${name}`;
badge.style.position = "absolute";
badge.style.left = `${left}px`;
badge.style.top = `${top - 30}px`;
badge.style.background = "#1e8449";
badge.style.color = "white";
badge.style.padding = "4px 6px";
badge.style.borderRadius = "4px";
badge.style.fontSize = "16px";
badge.style.whiteSpace = "nowrap";
badge.style.pointerEvents = "none";
badge.style.zIndex = "999999";
overlay.appendChild(badge);
});
// ----------------------
// 2. ARIA RADIO-GROUPS
// ----------------------
document.querySelectorAll('[role="radiogroup"]').forEach(rg => {
const accName = getAccessibleName(rg);
// Outline group
rg.style.outline = "3px solid #7d3c98";
// Position of the element
const rect = rg.getBoundingClientRect();
const left = rect.left + window.scrollX;
const top = rect.top + window.scrollY;
// Floating badge
const badge = document.createElement("div");
badge.textContent = `Radio-group: ${accName}`;
badge.style.position = "absolute";
badge.style.left = `${left}px`;
badge.style.top = `${top - 30}px`;
badge.style.background = "#7d3c98";
badge.style.color = "white";
badge.style.padding = "5px";
badge.style.borderRadius = "5px";
badge.style.fontSize = "16px";
badge.style.whiteSpace = "nowrap";
badge.style.pointerEvents = "none";
badge.style.zIndex = "999999";
overlay.appendChild(badge);
});
11. Display focusable elements:
This simple script logs each element as it receives keyboard focus. Press TAB through the page, and you’ll see every focusable element listed in the console:
View the script
document.addEventListener('focusin', () => {
console.log('Focused element:', document.activeElement);
});
12. Display aria-owns:
View the script
// ----------------------
// Scroll-safe overlay container
// ----------------------
const overlay = document.createElement("div");
overlay.style.position = "absolute";
overlay.style.top = "0";
overlay.style.left = "0";
overlay.style.width = "100%";
overlay.style.pointerEvents = "none";
overlay.style.zIndex = "999999";
document.body.appendChild(overlay);
// Colour for aria-owns highlights
const ownsColor = "#c2185b"; // pink-ish
// ----------------------
// Main logic
// ----------------------
document.querySelectorAll("[aria-owns]").forEach(owner => {
const ownsValue = owner.getAttribute("aria-owns");
if (!ownsValue || !ownsValue.trim()) {
return;
}
const ids = ownsValue.trim().split(/\s+/);
// Outline the owner
owner.style.outline = `3px solid ${ownsColor}`;
// Position for the owner's badge
const ownerRect = owner.getBoundingClientRect();
const ownerLeft = ownerRect.left + window.scrollX;
const ownerTop = ownerRect.top + window.scrollY;
// Badge for the owner element
const ownerBadge = document.createElement("div");
ownerBadge.textContent = `aria-owns: ${ownsValue}`;
ownerBadge.style.position = "absolute";
ownerBadge.style.left = `${ownerLeft}px`;
ownerBadge.style.top = `${ownerTop - 30}px`;
ownerBadge.style.background = ownsColor;
ownerBadge.style.color = "white";
ownerBadge.style.padding = "5px";
ownerBadge.style.borderRadius = "5px";
ownerBadge.style.fontSize = "16px";
ownerBadge.style.whiteSpace = "nowrap";
ownerBadge.style.pointerEvents = "none";
ownerBadge.style.zIndex = "999999";
overlay.appendChild(ownerBadge);
// Highlight each owned element
ids.forEach(id => {
const owned = document.getElementById(id);
if (!owned) {
// Optional: log missing references to the console
console.warn(`aria-owns references missing element with id="${id}"`, owner);
return;
}
// Outline the owned element (dashed to distinguish from owner)
owned.style.outline = `3px dashed ${ownsColor}`;
const rect = owned.getBoundingClientRect();
const left = rect.left + window.scrollX;
const top = rect.top + window.scrollY;
const ownedBadge = document.createElement("div");
ownedBadge.textContent = `owned: #${id}`;
ownedBadge.style.position = "absolute";
ownedBadge.style.left = `${left}px`;
ownedBadge.style.top = `${top - 24}px`;
ownedBadge.style.background = ownsColor;
ownedBadge.style.color = "white";
ownedBadge.style.padding = "3px 5px";
ownedBadge.style.borderRadius = "5px";
ownedBadge.style.fontSize = "14px";
ownedBadge.style.whiteSpace = "nowrap";
ownedBadge.style.pointerEvents = "none";
ownedBadge.style.zIndex = "999999";
overlay.appendChild(ownedBadge);
});
});
13. Display aria-controls:
View the script
// ----------------------
// Scroll-safe overlay container
// ----------------------
const overlay = document.createElement("div");
overlay.style.position = "absolute";
overlay.style.top = "0";
overlay.style.left = "0";
overlay.style.width = "100%";
overlay.style.pointerEvents = "none";
overlay.style.zIndex = "999999";
document.body.appendChild(overlay);
// Colour for aria-controls highlights
const controlsColor = "#00796b"; // teal
// ----------------------
// Main logic
// ----------------------
document.querySelectorAll("[aria-controls]").forEach(controller => {
const controlsValue = controller.getAttribute("aria-controls");
if (!controlsValue || !controlsValue.trim()) {
return;
}
const ids = controlsValue.trim().split(/\s+/);
// Outline the controller element
controller.style.outline = `3px solid ${controlsColor}`;
// Coordinates for controller badge
const rect = controller.getBoundingClientRect();
const left = rect.left + window.scrollX;
const top = rect.top + window.scrollY;
// Badge for the controller
const controllerBadge = document.createElement("div");
controllerBadge.textContent = `aria-controls: ${controlsValue}`;
controllerBadge.style.position = "absolute";
controllerBadge.style.left = `${left}px`;
controllerBadge.style.top = `${top - 30}px`;
controllerBadge.style.background = controlsColor;
controllerBadge.style.color = "white";
controllerBadge.style.padding = "5px";
controllerBadge.style.borderRadius = "5px";
controllerBadge.style.fontSize = "16px";
controllerBadge.style.whiteSpace = "nowrap";
controllerBadge.style.pointerEvents = "none";
controllerBadge.style.zIndex = "999999";
overlay.appendChild(controllerBadge);
// Highlight each controlled element
ids.forEach(id => {
const controlled = document.getElementById(id);
if (!controlled) {
console.warn(`aria-controls references missing element with id="${id}"`, controller);
return;
}
// Outline controlled element (dashed to distinguish)
controlled.style.outline = `3px dashed ${controlsColor}`;
const cRect = controlled.getBoundingClientRect();
const cLeft = cRect.left + window.scrollX;
const cTop = cRect.top + window.scrollY;
const controlledBadge = document.createElement("div");
controlledBadge.textContent = `controls: #${id}`;
controlledBadge.style.position = "absolute";
controlledBadge.style.left = `${cLeft}px`;
controlledBadge.style.top = `${cTop - 24}px`;
controlledBadge.style.background = controlsColor;
controlledBadge.style.color = "white";
controlledBadge.style.padding = "3px 5px";
controlledBadge.style.borderRadius = "5px";
controlledBadge.style.fontSize = "14px";
controlledBadge.style.whiteSpace = "nowrap";
controlledBadge.style.pointerEvents = "none";
controlledBadge.style.zIndex = "999999";
overlay.appendChild(controlledBadge);
});
});
14. Display focus order:
View the script
// ----------------------
// Focus order tracker (number as you TAB)
// ----------------------
let focusStep = 0;
// Create one floating badge for the currently focused element
const focusBadge = document.createElement("div");
focusBadge.style.position = "absolute";
focusBadge.style.background = "#111";
focusBadge.style.color = "white";
focusBadge.style.padding = "5px 8px";
focusBadge.style.borderRadius = "6px";
focusBadge.style.fontSize = "16px";
focusBadge.style.whiteSpace = "nowrap";
focusBadge.style.pointerEvents = "none";
focusBadge.style.zIndex = "999999";
document.body.appendChild(focusBadge);
function getLabel(el) {
// Small, readable label to help identify the element
const tag = el.tagName.toLowerCase();
const id = el.id ? `#${el.id}` : "";
const role = el.getAttribute("role");
const name =
(el.getAttribute("aria-label") || "").trim() ||
(el.textContent || "").trim().slice(0, 40);
const roleText = role ? `[role="${role}"]` : "";
const nameText = name ? ` "${name.replace(/\s+/g, " ")}"` : "";
return `${tag}${id}${roleText}${nameText}`;
}
function placeBadge(el) {
const rect = el.getBoundingClientRect();
const left = rect.left + window.scrollX;
const top = rect.top + window.scrollY;
focusBadge.style.left = `${left}px`;
focusBadge.style.top = `${top - 30}px`;
}
function onFocusIn(e) {
const el = e.target;
if (!el || el === document.body || el === document.documentElement) return;
focusStep += 1;
// Outline the focused element so it’s obvious
el.style.outline = "3px solid #111";
// Update badge content + position
focusBadge.textContent = `${focusStep}. ${getLabel(el)}`;
placeBadge(el);
}
// Keep the badge aligned if the page scrolls/resizes while focused
function onScrollOrResize() {
const el = document.activeElement;
if (!el || el === document.body || el === document.documentElement) return;
placeBadge(el);
}
document.addEventListener("focusin", onFocusIn, true);
window.addEventListener("scroll", onScrollOrResize, true);
window.addEventListener("resize", onScrollOrResize, true);
console.log("Focus order tracker active. Press Tab to step through focusable elements.");
Why not convert these into bookmarklets?
You can convert any of these snippets into bookmarklets, but for teaching and quick testing, pasting JavaScript into the console is often faster and more flexible. Bookmarklets need to be encoded, saved, and managed manually in your browser. In contrast, running scripts in the console lets you:
- adjust or experiment with the code before running it
- see errors or warnings immediately
- change the snippet based on the current page structure
- avoid cluttering your browser with one-off bookmarklets
- keep the focus on understanding what the script is doing, not just clicking a shortcut
Using the console also mirrors how real accessibility debugging works — quick checks, small iterations, and rapid feedback.
Conclusion
These simple scripts are designed to help you understand how accessibility features appear in the browser.
They’re not a replacement for manual testing or assistive technologies, but they can make patterns, errors, and relationships much easier to see while testing a page.