◆ 子要素を Shadow DOM 内に表示するときに毎回新規のものにしたい
  ◆ タブやルートだと表示のたびに初期状態にしたい
◆ slot だとすでにある DOM を表示するかどうかなので同じものの使いまわし
◆ template タグで子要素を囲んで slot の代わりに template.content をクローンしたのを配置する

slot の挙動

Shadow DOM を使ったときにホスト要素の子要素を Shadow DOM 内に表示するとき slot を使います
これが表示されるときに中身を作ってくれるといいのですが 実際は表示状態に関わらずに事前に中身が作られて slot タグがあれば表示されるだけです

例でこういうページを用意しました
プレビュー機能で実際に見れます

<!DOCTYPE html>

<script>
customElements.define("foo-bar", class extends HTMLElement {
constructor() {
super()
console.log("created")

this.attachShadow({ mode: "open" }).innerHTML = `
<h1>This is foo-bar element.</h1>
`
}

connectedCallback() {
console.log("connected")
}
})

customElements.define("visibility-switch", class extends HTMLElement {
constructor() {
super()
this.attachShadow({ mode: "open" }).innerHTML = `
<button name="show">Show</button>
<button name="hide">Hide</button>
<div id="container"></div>
`

const container = this.shadowRoot.getElementById("container")

this.shadowRoot.addEventListener("click", eve => {
if (eve.target.name === "show") {
container.innerHTML = `<slot></slot>`
} else if (eve.target.name === "hide") {
container.innerHTML = ""
}
})
}
})
</script>

<visibility-switch>
<foo-bar></foo-bar>
</visibility-switch>

visibility-switch という要素があり これは Show/Hide ボタンがあって Show を押すと slot 要素を Shadow DOM 内に作って子要素を表示します
Hide のほうは slot 要素を削除して子要素を非表示にします
子要素には foo-bar という要素を設置していて この要素が表示されれば「This is foo-bar element.」 というテキストが画面に出ます
foo-bar 要素では constructor と connectedCallback で console.log をするのでこれらの実行タイミングがわかります

動かして見ると console.log の出力は開いた直後にあり ボタンを押して表示を切り替えてもそれ以降は出力されません

表示するタイミングで中身を作って欲しい

機能的にこれはこれで自然だとは思います
しかし 表示するタイミングで中身を作って欲しいと思うことがあります

例えばタブを作るときのそれぞれの要素

<tab-item>
<h1>AAAAA</h1>
<elem-1></elem-1>
<elem-2></elem-2>
</tab-item>
<tab-item>
<h1>BBBB</h1>
<elem-3></elem-3>
</tab-item>

こういうものがあったとき アクティブなタブ以外の中身は表示だけじゃなくて実体も消したいですし タブを開いたタイミングで新規に作って欲しいです
タブの切り替えで前回の状態が残らない初期状態に戻したいです
また この HTML を読み込んだときに必要ないタブの中身まで初期化処理が入るので タブが多かったり重い処理のタブがあるとページを開いた直後に中身がほとんどないタブでも遅くなります

子要素に書かずに

<tab-item element="tab1-content"></tab-item>

のように要素名を指定して slot の代わりにこの子要素を配置・削除すれば実現できますが タブごとに Custom Element を定義しておかないといけなくなります
そんな手間をかけず単純に子要素に書いて済ませたいものもあります

対処方法

タブの例だと作る部分が増えるので さっきの visibility-switch 要素を対応させます

表示のタイミングで新しいものを作るというのは自分で JavaScript で処理するしかなさそうです
その場合は slot は要らなくなります

まずは中身部分を template タグでまとめます

<visibility-switch>
<template>
<foo-bar></foo-bar>
</template>
</visibility-switch>

切り替えの処理で表示するときに template の中身をクローンし slot タグの代わりに配置します

	this.shadowRoot.addEventListener("click", eve => {
container.innerHTML = ""
if (eve.target.name === "show") {
const tpl = this.querySelector(":scope>template")
container.append(tpl.content.cloneNode(true))
}
})

全体はこうなります
foo-bar 要素が表示状態になるたびに constructor が呼び出されて console.log の出力が表示されます

<!DOCTYPE html>

<script>
customElements.define("foo-bar", class extends HTMLElement {
constructor() {
super()
console.log("created")

this.attachShadow({ mode: "open" }).innerHTML = `
<h1>This is foo-bar element.</h1>
`
}

connectedCallback() {
console.log("connected")
}
})

customElements.define("visibility-switch", class extends HTMLElement {
constructor() {
super()
this.attachShadow({ mode: "open" }).innerHTML = `
<button name="show">Show</button>
<button name="hide">Hide</button>
<div id="container"></div>
`

const container = this.shadowRoot.getElementById("container")

this.shadowRoot.addEventListener("click", eve => {
container.innerHTML = ""
if (eve.target.name === "show") {
const tpl = this.querySelector(":scope>template")
container.append(tpl.content.cloneNode(true))
}
})
}
})
</script>

<visibility-switch>
<template>
<foo-bar></foo-bar>
</template>
</visibility-switch>