I'm trying to apply ::selection
style on slotted elements within a web component.
Here is a small code to illustrates the issue:
window.customElements.define('x-widget', class extends HTMLElement {
constructor() {
super();
this.attachShadow({mode: 'open'});
const template = document.createElement('template');
template.innerHTML = `
<div>TEMPLATE</div>
<div><slot></slot></div>
`;
const style = document.createElement('style');
style.textContent = `
:host {
display: content;
contain: content;
color: red;
}
:host::selection, ::selection {
background: red;
color: white;
}
::slotted(::selection) {
background: red;
color: white;
}
`;
this.shadowRoot.appendChild(style);
this.shadowRoot.appendChild(template.content.cloneNode(true));
}
});
<x-widget>CONTENT1</x-widget>
<x-widget><div>CONTENT2</div></x-widget>
Here is a demo: https://jsfiddle.net/ov4xmqsr/
The selection style is applied to all texts excepts <div>CONTENT2</div>
. Is there a way to use pseudo-element selectors within the component?
You can't, because slotted content is NOT moved to shadowDOM, it remains in ligthDOM.
You style slotted content in ligthDOM (in this case the main DOM)
For very detailed answer see: ::slotted CSS selector for nested children in shadowDOM slot
I added extra CSS to show:
Using variables (that penetrate shadowDOM) to declare a colors ones
Using a #selectable
DIV wrapper selects both custom elements
See for yourself what the x-widget ::selection
selector would do
Select all text:
<div id=selectable>
<x-widget>CONTENT1</x-widget>
<x-widget><div>CONTENT2</div></x-widget>
</div>
<style>
body {
--selectionBackground: green; --selectionColor: white;
font-size: 2em;
}
#selectable ::selection {
background: var(--selectionBackground); color: var(--selectionColor);
font-weight: bold;
}
</style>
<script>
window.customElements.define('x-widget', class extends HTMLElement {
constructor() {
const template = document.createElement('template');
template.innerHTML = `<div>TEMPLATE</div><div><slot></slot></div>`;
const style = document.createElement('style');
style.textContent = `
::selection { /* colors only template text, not slot content */
background: var(--selectionBackground);
color: var(--selectionColor);
}
::slotted(*) { /* selectors select HTMLElements! */
color: red; /* CONTENT1 is TEXT, NOT an HTMLElement! */
}`;
super().attachShadow({mode: 'open'})
.append(style, template.content.cloneNode(true));
}});
</script>