While there is no CSS native way to do this, you can select your custom elements using js and apply styles to them.
const customEls = Array.from(
document.querySelectorAll(`*`)
).filter(
n => n.tagName?.startsWith('CUSTOM-')
);
customEls.forEach(
el => el.classList.add('ready')
);
You can also use MutationObserver to catch any custom elements added to the DOM. Let's say you want to make all undefined custom elements from your library be display:none until after their module definitions have loaded to prevent a Flash of Unstyled Content while not unintentionally affecting any other undefined components. Just add this magic little js snippet before ANY other DOM element is loaded. Specifically, this script tag must go OUTSIDE your <html> element, directly below the <!DOCTYPE html> declaration and before ANY other element.
<!DOCTYPE html>
<script>
const style = document.createElement('style');
document.head.appendChild(style);
const tagPrefix = 'custom-';
const rule = ':not(:defined) { display: none; }';
const observer = new MutationObserver(mutations => {
const pre = tagPrefix.toLowerCase();
for (const m of mutations) {
for (const node of m.addedNodes) {
const t = node.tagName?.toLowerCase();
if (node.nodeType === 1 && t.startsWith(pre)) {
style.textContent += t + rule + "\n";
}
}
}
});
observer.observe(document, {
childList: true, subtree: true
});
</script>
<title>Custom Elements Partial Name Selector</title>
<custom-element-1> test </custom-element-1>
<custom-element-2> test </custom-element-2>
<script>
customElements.define(
'custom-element-1', class extends HTMLElement {}
);
</script>
This works due to this note in HTML5 - 8.2.5 Tree Construction :
When the parser reaches a script element, even before the tag is encountered, it switches to the "in head" insertion mode. This allows scripts to execute during the "initial" and "before html" insertion modes, which is why scripts can run and manipulate the DOM even before explicit structural elements are parsed.
You can load this from an external file, just make sure it's cached for best performance and do not make it async or type="module" or it will not work. Additionally, you can set styles on the object from within it's own definition.
<!DOCTYPE html>
<script src="./not-defined.js"></script>
<title> External Script Example </title>
<style> .green { background: green; } </style>
<another-element> Should be visible </another-element>
<custom-element-1> Should be hidden </custom-element-1>
<custom-element-2> Should be green </custom-element-2>
<script>
customElements.define('custom-element-2',
class TestElement extends HTMLElement {
constructor() { super(); this.classList.add('green'); }
});
</script>
-), so<foo>is invalid while<foo-bar>is valid.