Guía educativa de selectores de custom elements y Shadow DOM
Dónde puede actuar cada selector
Compara la hoja que contiene la regla, el sujeto que recibe el estilo y el límite de encapsulación que atraviesa cada forma.
Estado y host
El custom element es el host de su shadow root. Una regla interna usa :host o :host-context(); una regla de la página puede usar el nombre del elemento y :state(active).
Host
:hostSelecciona el host desde una hoja dentro de su shadow root.
Especificidad(0, 1, 0)
Host
:hostComportamiento
- La regla interna puede estilizar el propio custom element.
- No exige clase, atributo ni estado propio en el host.
Ejemplos
La regla :host se coloca dentro del shadow root; el HTML muestra el host en la página.
:host<baseline-shadow-card>
</baseline-shadow-card>Recibe el estilo: Host del custom element
Errores frecuentes
- Escribir :host en una hoja de la página no equivale a una regla interna.
- El host no es un descendiente ordinario del shadow root para cualquier selector.
Clase del host
:host(.selected)Selecciona el host si tiene la clase selected.
Especificidad(0, 2, 0)
Clase del host
:host(.selected)Comportamiento
- El argumento de :host() filtra el propio host.
- La clase es visible en HTML y distinta del estado guardado en ElementInternals.states.
Ejemplos
El HTML incluye class="selected" en el host; la regla se coloca dentro del shadow root.
:host(.selected)<baseline-shadow-card class="selected">
</baseline-shadow-card>Recibe el estilo: Host del custom element
Errores frecuentes
- Confundir .selected con :state(active): son condiciones independientes.
- Aplicar la clase a un hijo interno no satisface :host(.selected).
Estado propio del host
:host(:state(active))Selecciona el host con el estado propio active desde su hoja interna.
Especificidad(0, 2, 0)
Estado propio del host
:host(:state(active))Comportamiento
- El componente activa el estado mediante ElementInternals.states.add("active").
- El estado no se serializa como clase o atributo del HTML mostrado.
Ejemplos
El HTML por sí solo no expresa el estado: el JS generado llama setActive(true) antes de comprobar la regla interna.
:host(:state(active))<baseline-shadow-card>
</baseline-shadow-card>Recibe el estilo: Host del custom element
Errores frecuentes
- Buscar un atributo active en el HTML para explicar :state(active).
- Tratar la aceptación de la sintaxis como prueba de que la regla aplicó estilo.
Soporte y compatibilidad
Consulta el estado Baseline de :state() y abre su enlace para ver el detalle por navegador. El playground comprueba si esta regla interna aplica estilo aquí.
Estado desde la página
baseline-shadow-card:state(active)Selecciona desde la página el custom element con estado active.
Especificidad(0, 1, 1)
Estado desde la página
baseline-shadow-card:state(active)Comportamiento
- La regla externa alcanza el host, sin entrar en su shadow root.
- Observa el mismo CustomStateSet que usa la forma interna :host(:state(active)).
Ejemplos
El JS generado activa el estado del host; esta regla CSS pertenece a la página.
baseline-shadow-card:state(active)<baseline-shadow-card>
</baseline-shadow-card>Recibe el estilo: Host del custom element
Errores frecuentes
- Creer que la regla de página puede seleccionar nodos internos por ser active el host.
- Sustituir el estado propio por una clase y presentarlo como la misma prueba.
Soporte y compatibilidad
Esta forma usa :state() en la hoja de la página. La tarjeta muestra su estado Baseline; el playground comprueba el estilo en este navegador.
Contexto del host
:host-context(.theme-active)Selecciona el host desde su hoja interna si él o un ancestro externo tiene la clase theme-active.
Especificidad(0, 2, 0)
Contexto del host
:host-context(.theme-active)Comportamiento
- La condición mira el contexto que rodea al host, aunque la regla CSS vive dentro del shadow root.
- El sujeto que recibe el estilo sigue siendo el host.
Ejemplos
El div exterior tiene theme-active; el CSS :host-context(.theme-active) se escribe dentro del shadow root.
:host-context(.theme-active)<div class="theme-active">
<baseline-shadow-card>
</baseline-shadow-card>
</div>Recibe el estilo: Host del custom element
Errores frecuentes
- Escribir :host-context() en la hoja de la página.
- Interpretar la coincidencia como permiso para seleccionar cualquier nodo interno desde fuera.
Soporte y compatibilidad
Su disponibilidad todavía es limitada. Abre el enlace de la tarjeta para ver el detalle por navegador y prueba el efecto de theme-active en el playground.
Slots y partes
Un slot proyecta hijos de la página; :has-slotted comprueba si recibió contenido. Una parte expone una superficie interna para que la página la estilice.
Elemento asignado
slot[name="content"]::slotted(.item)Selecciona el elemento .item asignado directamente al slot content.
Especificidad(0, 2, 2)
Elemento asignado
slot[name="content"]::slotted(.item)Comportamiento
- La regla se escribe dentro del shadow root, junto al slot.
- El sujeto es un hijo de luz asignado; el segundo bloque HTML muestra el slot interno.
Ejemplos
El span pertenece al HTML de la página y se distribuye al slot content del shadow root.
slot[name="content"]::slotted(.item)<baseline-shadow-card>
<span slot="content" class="item">Contenido asignado</span>
</baseline-shadow-card><div part="panel">
<slot name="content"></slot>
</div>Recibe el estilo: Elemento asignado al slot
Errores frecuentes
- Esperar que ::slotted(.item) alcance todos los descendientes del elemento asignado.
- Contar coincidencias desde document.querySelectorAll() como si evaluara la regla interna.
Slot con contenido
slot[name="content"]:has-slottedSelecciona el slot content cuando tiene nodos asignados.
Especificidad(0, 2, 1)
Slot con contenido
slot[name="content"]:has-slottedComportamiento
- La regla vive dentro del shadow root y estiliza el propio slot.
- También pueden satisfacer la condición nodos de texto asignados; esta demo usa un span.
Ejemplos
El span de la página se asigna al slot interno; al quitarlo, el slot deja de cumplir :has-slotted.
slot[name="content"]:has-slotted<baseline-shadow-card>
<span slot="content" class="item">Contenido asignado</span>
</baseline-shadow-card><div part="panel">
<slot name="content"></slot>
</div>Recibe el estilo: Slot dentro del shadow root
Errores frecuentes
- Confundir :has-slotted con ::slotted(.item): seleccionan sujetos distintos.
- Suponer que la regla selecciona el span asignado en lugar del slot.
Soporte y compatibilidad
Su disponibilidad todavía es limitada. Abre el enlace de la tarjeta para ver el detalle por navegador y prueba el slot con y sin contenido asignado.
Parte expuesta
baseline-shadow-card::part(panel)Estiliza desde la página el panel interno expuesto como part="panel".
Especificidad(0, 0, 2)
Parte expuesta
baseline-shadow-card::part(panel)Comportamiento
- El componente declara explícitamente qué elemento interno expone.
- La regla de página se aplica a esa parte, sin abrir el resto de su árbol interno.
Ejemplos
El panel con part="panel" vive dentro del shadow root; la regla ::part(panel) vive en la página.
baseline-shadow-card::part(panel)<baseline-shadow-card>
</baseline-shadow-card><div part="panel">
<slot name="content"></slot>
</div>Recibe el estilo: Panel interno con part="panel"
Errores frecuentes
- Suponer que ::part(panel) deja seleccionar descendientes internos arbitrarios.
- Esperar que una parte anidada atraviese varios componentes sin exportparts.
Límites y soporte
El resultado comprueba que la regla se acepta, que funciona en una prueba positiva independiente y que su propiedad testigo aparece en el sujeto actual. No es un recuento de querySelectorAll().
exportparts
exportparts sirve para reenviar una parte a través de otro componente anidado. Este escenario tiene un solo shadow root y no lo necesita.
querySelectorAll()
Una consulta desde la página no atraviesa el shadow root. ::slotted() y ::part() representan estilos en un contexto CSS; sus consultas DOM no ofrecen un recuento comparable.