Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

92
Visualizações
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 Respostas
Responde à pergunta

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 Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda