<!-- From: https://gist.github.com/samthor/7b307408e73784971ef0fcf4a8af6edd -->
<script src="https://cdn.rawgit.com/samthor/7b307408e73784971ef0fcf4a8af6edd/raw/81f168d4f2ab3fd86825e073f60240c3ef2988bd/shadowlisten.js"></script>
<p>
This is an adjunct to <a id="link" href="https://medium.com/@samthor/focus-inside-shadow-dom-78e8a575b73" target="_blank">an article on Medium</a>.
It shows off observing the actual focused node, even inside shadow roots.
It uses <a id="library" href="https://gist.github.com/samthor/7b307408e73784971ef0fcf4a8af6edd" target="_blank">a library</a> that emits custom <code>-shadow-focus</code> events (even for regular focus) with the <code>detail</code> property set to the actual focus target.
</p>
<p>
Input elements that are not in a shadow root are highlighted in <span class="blue">blue</span>.
</p>
<div id="div">
<input placeholder="light DOM" id="light_dom" />
</div>
<template id="t">
<h2>Shadow #1</h2>
<style>
h2 {
font: inherit;
margin: 0;
}
:host {
background: rgba(255, 0, 0, 0.5);
padding: 12px;
}
</style>
<input id="one" placeholder="one" />
<slot></slot>
<input id="two" placeholder="two" />
<div id="internal"></div>
</template>
<template id="t2">
<h2>Shadow #2</h2>
<style>
h2 {
font: inherit;
margin: 0;
}
:host {
background: rgba(0, 255, 0, 0.5);
padding: 12px;
}
</style>
<input id="sub-one" placeholder="sub-one" />
<input id="sub-two" placeholder="sub-two" />
</template>
<input id="other" placeholder="outside" />
<h2>List of recently focused nodes</h2>
<ul id="log"></ul>
body {
max-height: 100vh;
overflow: hidden;
}
input {
border: 1px solid blue
}
.blue {
border: 1px solid blue;
}
li em {
font-style: normal;
opacity: 0.5;
}
View Compiled
if (!div.attachShadow) {
div.textContent = 'Your browser does not support Shadow DOM :(';
throw new Error();
}
// This line adds the helper library. It then generates `-shadow-focus` events, which can be listened to...
document.addEventListener('focus', shadowFocusHandler, true);
// ... here! The `ev.detail` message
document.addEventListener('-shadow-focus', function(ev) {
console.info('got -shadow-focus', ev.detail, 'real target', ev.target);
const target = ev.detail;
const msg = document.createElement('li');
msg.textContent = format(ev.detail);
if (ev.target !== ev.detail) {
msg.innerHTML += ` <em>${format(ev.target)}</em>`;
}
log.insertBefore(msg, log.firstElementChild);
window.setTimeout(_ => msg.remove(), 2500);
});
const root = div.attachShadow({mode: 'open'});
root.appendChild(t.content.cloneNode(true));
const root2 = root.getElementById('internal').attachShadow({mode: 'open'});
root2.appendChild(t2.content.cloneNode(true));
function format(el) {
let out = '';
if (el) {
out += el.localName;
if (el.id) {
out += '#' + el.id;
}
if (el.className) {
out += '.' + el.className;
}
}
return out;
}
View Compiled
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.