Kavinda Jayakody
Kavinda Jayakody

Reputation: 786

Styling default slot in webcomponents

In webcomponents, we have two type of slots (named slots and default slots). We can easily style named slots by using syntax slot[name]::slotted(*). But is there any way that we can style default slots because they don't have any name associated?

The code is something like this and i'm using Angular Elements.

<div class="topbar-item">
  <slot class="icon" name="icon"></slot>
  <span class="text">
   <slot></slot> <-- This is the slot i want to add styles, only if the slot has some data assigned. (need to add margin-left)
  </span>
</div>

Upvotes: 3

Views: 6402

Answers (3)

It is a misconception slotted content is MOVED to slots in shadowDOM

It is NOT!;

It remains invisible in lightDOM and is REFLECTED to its SLOT in shadowDOM

That means you can apply styles after content has been slotted (mouseover in the code below)

Or.. to style UNnamed slots, you style the UNnamed content in lightDOM:

For a really deep dive explanation see: ::slotted CSS selector for nested children in shadowDOM slot

customElements.define("my-element", class extends HTMLElement {
  connectedCallback() {
    let template = document.getElementById(this.nodeName);
    this.attachShadow({mode:'open'})
        .append(template.content.cloneNode(true));
  }
})
my-element div {
  background: lightcoral;
  padding: 1em;
  margin-top:.5em;
}

my-element div:hover {
  background: lightgreen;
}

h1{
  background:lightblue;
  color:black;
  margin:0;
}
h1:hover {
  color: red;
}
<template id=MY-ELEMENT>
  <style>
    :host {
      display: block;
      padding:.5em;
      background:green;
    }
    ::slotted(*){
      color:white;
    }
    div{
      border:1px dashed black;
    }
  </style>
  <div>
  <slot name=title></slot>
  <slot></slot>
  </div>
</template>

<my-element>
  <div>Custom Elements Rule!</div>
  <h1 slot=title>Hello World!</h1>
  <div>What a wonderfull day!</div>
</my-element>

Note! how all unnamed content goes into the (one) unnamed SLOT

Upvotes: 2

lamplightdev
lamplightdev

Reputation: 2071

You can just use the :not() pseudo-class:

<style>
...

slot:not([name])::slotted(*) {
  ...
}

...
</style>

Upvotes: 2

Kavinda Jayakody
Kavinda Jayakody

Reputation: 786

Found a little workaround until someone finds a better way. We can use slotchange event to make sure whether any items attached to the slot or not. In this way.

HTML

<slot (slotchange)="onSlotChanged($event)"></slot>

JS/TS

    onSlotChanged($event) {
       const slotHasData = $event.target.assignedNodes().length > 0;
       // Is event.target.assignedNodes().length return more than 0, it has nu of items attached to the slot
    }

Upvotes: 0

Related Questions