Use axe core to put ugly borders around elements that are not accessible
import axe from 'axe-core'; | |
function debounce(fn, wait) { | |
let timeout = null; | |
return function (...args) { | |
const next = () => fn.apply(this, args); | |
clearTimeout(timeout); | |
timeout = setTimeout(next, wait); | |
}; | |
} | |
/** | |
* Not all elements support shadow dom (such as image) ascent the parent tree until the closest element is found | |
* | |
* @param {HTMLElement} node | |
* @returns | |
*/ | |
function resolveClosestShadowRoot(node) { | |
if (!node) { | |
return null; | |
} | |
if (node.attachShadow) { | |
return node; | |
} | |
return resolveClosestShadowRoot(node.parentElement); | |
} | |
/** | |
* Places a red boarder on an Element | |
* | |
* @param {HTMLElement} node | |
*/ | |
function styleNode(node) { | |
// does the browser support shadow dom? | |
if (!document.head.attachShadow) { | |
return; | |
} | |
// has the node been GC'd | |
if (!node) { | |
return; | |
} | |
try { | |
const resolvedNodeToShadow = resolveClosestShadowRoot(node); | |
// if we can't resolve a node to shadow, or the node to shadow has a shadow dom already, skip | |
if (!resolvedNodeToShadow || resolvedNodeToShadow.shadowRoot) { | |
return; | |
} | |
try { | |
const shadowRoot = resolvedNodeToShadow.attachShadow({ mode: 'open' }); | |
shadowRoot.innerHTML = '<style>:host { outline: red solid 1rem; }</style><slot></slot>'; | |
} catch (e) { | |
styleNode(resolvedNodeToShadow.parentNode); | |
} | |
} catch (e) {} | |
} | |
function domChange() { | |
axe.run({ | |
elementRef: true, | |
runOnly: ['wcag2a', 'wcag2aa', 'wcag21a', 'wcag21aa'], | |
}).then((results) => { | |
console.group('A11y Errors'); | |
results?.violations?.forEach((violation) => { | |
console.error(violation); | |
// do we have the shadow dom feature? and do we visually allow a11y checker | |
if (document.head.attachShadow) { | |
violation.nodes.forEach((axeNode) => styleNode(axeNode.element)); | |
} | |
}); | |
if (results?.violations?.length > 0) { | |
console.error( | |
'Accessibility violations found.', | |
); | |
} | |
console.groupEnd('A11y Errors'); | |
}); | |
} | |
const debounceObserve = debounce(domChange, 1000); | |
const observer = new MutationObserver(debounceObserve); | |
observer.observe(document.querySelector('body'), { childList: true, subtree: true }); | |
document.addEventListener('DOMContentLoaded', debounceObserve); | |
console.log('initalizing a11y detector'); | |
setTimeout(debounceObserve, 0); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment