Unfortunately, targeting the Nth element in a web component shadow DOM with CSS ::part() is not possible. The css-shadow-parts spec explicitly states that ::part() cannot be used with pseudo-classes that match based on tree information. This includes the Nth selector.
However, there is a workaround. You can use multiple part names to achieve the same effect. For example, you could use input input-1
to target the first input element within a web component.
customElements.define("web-component", class extends HTMLElement { constructor() { super(); this.attachShadow({mode: "open"}); this.size = this.getAttribute('size'); this.template = document.createElement("template"); this.template.innerHTML = '<style>' +':host {white-space: nowrap}' +'input {text-align:center;width: 3ch;height: 3ch}' +'input:not(:last-child){margin-right:.5ch}' +'</style>' this.render(); } render() { this.shadowRoot.appendChild(this.template.content.cloneNode(true)); for (let i = 0; i < this.size; i++) { const input = document.createElement('input'); input.setAttribute('part','input input-'+(i+1)); input.type = "text"; this.shadowRoot.appendChild(input); } } } );
web-component::part(input input-1) { background: #ff00ff; } web-component::part(input) { border: 2px solid orange; }
<web-component size="6" id="shadow-dom-host"></web-component>
Another potential issue to watch out for is the timing of the connectedCallback
. This callback is fired when the web component is inserted into the DOM. However, the DOM may not be fully parsed at this point. This means that if you try to access the web component's shadow DOM from within the connectedCallback
, you may get unexpected results.
To avoid this problem, you should wait until the DOMContentLoaded
event fires before accessing the web component's shadow DOM. This ensures that the DOM is fully parsed and ready for use.