Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

96
Vistas
Stenciljs: What is the right way to prepend/append Slot elements?

I am having some trouble with the lifecycle methods in web components.

We want to dynamically order child elements being passed in as slots.

To illustrate, this web component takes a prop, iconPos, and will determine whether the icon will be placed at the start or end of the slot.

<my-component iconPos="start"> 
   <img src="/path/icon.svg" /> 
   <div>{this.list}</div> 
</my-component>

I haven't had any luck getting it working with ref:

dc6b89e7.js:2926 TypeError: Cannot read properties of undefined (reading 'prepend')

Here's what I have so far:

 @State() slotElement!: HTMLDivElement;
 @Prop() iconPos: 'start' | 'end';
...

  private createSlots() {
    switch (this.iconPos) {
      case 'start':
        this.slotElement.prepend(<img />);
        break;
      case 'end':
        this.slotElement.append(<img />);
        break;
      default:
        throw new Error(
          `Invalid value \`${this.iconPos}\`, passed into \`iconPos\`. Expected valid values are \`start\`, \`end\``.
        );
    }
  }

  render() {
    return (
    // iconPos="start"
      <parent-component>
        <div ref={(el) => (this.slotElement= el as HTMLDivElement)}>
          <slot></slot>
        </div>
      </parent-component>
    )
  }

I would prefer to not use a CSS solution if possible. Any help would be much appreciated!

about 4 years ago · Juan Pablo Isaza
1 Respuestas
Responde la pregunta

0

Slotted content is NOT MOVED to <slot> elements; it is reflected!!

So all styling and element operations must be done in "lightDOM"

For (very) long read see: ::slotted CSS selector for nested children in shadowDOM slot

That means you have to append your elements in ligtDOM with:

this.append(this.firstElementChild)

You can't read the <my-component> innerHTML before it is parsed; so you need to wait till the innerHTML elements are created. Thus you will see the DOM change.
A better method might be to not use <slot> and declare your icon and content as attributes, and have the Web Component create the HTML.

<style>
  span::after { content: attr(id) }
  #FOO { background: lightgreen }
</style>

<my-component>
  <span id="FOO"></span>
  <span id="BAR"></span>
</my-component>
<my-component reversed>
  <span id="FOO"></span>
  <span id="BAR"></span>
</my-component>

<script>
  window.customElements.define('my-component', class extends HTMLElement {
    constructor() {
      super().attachShadow({mode:'open'})
             .innerHTML = `<style>::slotted(span){background:gold}</style>
                           ${this.nodeName}<slot></slot><br>`;
    }
    connectedCallback() {
      setTimeout(() => { // make sure innerHTML is parsed!
        if (this.hasAttribute("reversed")) {
          this.append(this.firstElementChild);
        }
      })
    }
  });
</script>

about 4 years ago · Juan Pablo Isaza Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda