◆ static.js というモジュールが必要
◆ static.js の html 関数を代わりに使って タグ名部分を unsafeStatic 関数を通して埋め込む
◆ static.js の html 関数は lit-html の html を関数をラップしていて 事前にテンプレート文字列を置き換えて静的なものにしてから lit-html の処理に渡す

React の場合

React ではタグやコンポーネントを動的に変更できます

const Example = () => {
const [count, setCount] = useState(0)
const up = () => {
setCount((count + 1) % 10)
}
const Component = count < 5 ? "span" : "button"
return (
<div>
<button onClick={up}>{count}</button>
<Component>{Component}</Component>
</div>
)
}

0 ~ 9 をループするカウンターがあって カウントが 0 ~ 4 だと span でそれ以外だと button という風にタグを切り替えます

{count < 5 ? (
<span>span</span>
) : (
<button>button</button>
)}

のようにもできますが Component という変数に入れられるので事前にタグがわからない場合やパターンがとても多いケースにも対応できます

Lit の場合

Lit では基本的にはこういうことはできません
可変部分は ${} を使って それ以外はそのまま HTML として使われる仕組みです
タグ名のところに ${} を使ってもエラーです

類似記法の htm だと

html`
<${Component}>children</>
`

という記法ですが これができません

issue を探すと一応 対応はしているようです
https://github.com/lit/lit/issues/78

ただ static というものを使うようですが ドキュメントでそれらしい解説はありません
API のリファレンスがあるだけのようです
https://lit.dev/docs/api/static-html/

結構需要ある機能だと思うのですけどね

使い方も少し特殊で通常の lit-html とは別の static.js をインポートする必要があります
https://github.com/lit/lit/blob/lit-html%403.1.0/packages/lit-html/src/static.ts

仕組みとしては lit-html が処理する前にテンプレートと埋め込む値を前処理して変換してしまうという方法です
そのため html 関数も lit-html の通常のものではなく独自のものにする必要があり それが static.js からインポートできます

この html 関数では埋め込む値に unsafeStatic のようにマークされたものがあると テンプレートの文字列に含めてしまい lit-html が処理する段階ではタグ名の部分は埋め込み値ではなくただの文字列して静的なものになっています

return tag === "span"
? html`<span>${value}</span>`
: html`<button>${value}</button>`

みたいなものになっています

通常と違う html 関数を使ったり タグ名部分で unsafeStatic を使ったり あまり使いやすくないのがいまいちです

<!doctype html>
<script type="importmap">
{
"imports": {
"lit": "https://cdn.jsdelivr.net/gh/lit/dist@3/all/lit-all.min.js",
"lit/static-html.js": "https://cdn.jsdelivr.net/gh/lit/dist@3/all/lit-all.min.js"
}
}
</script>
<script type="module">
import { LitElement } from "lit"
import { staticHtml as html, unsafeStatic } from "lit/static-html.js"

class ExampleElement extends LitElement {
static properties = {
count: {},
}

constructor() {
super()
this.count = 0
}

up() {
this.count = (this.count + 1) % 10
}

render() {
const tagname = this.count < 5 ? "span" : "button"
const tag = unsafeStatic(tagname)
return html`
<button @click=${this.up}>${this.count}</button>
<${tag}>${tagname}</${tag}>
`
}
}

customElements.define("example-element", ExampleElement)
</script>
<example-element></example-element>

lit-html では static.js ですが lit では static-html.js としてエクスポートされます
また jsdelivr の CDN に用意されてる全部込みのバンドルでは html という名前がかぶるので staticHtml という名前でエクスポートされています