◆ タグ名は ${} で設定できない
◆ wire を使えば変えられるけどリテラルで書くことになる
  ◆ → 事前に全部タグをコード中に用意しないといけない
◆ wire() のタグ関数を直接呼び出して使えばできるが見づらい
◆ ${} には HTML 要素も入れられるので createElement したのを渡すほうがいいのかも

hyperHTML でタグを変更する

hyperHTML では変更できる場所が限定されていて text node 部分や属性の値は変更できますが タグ名は変更できません

import {bind, wire} from "https://cdn.jsdelivr.net/npm/hyperhtml@2.25.5/esm.js"

// change this
const tag = "div"

bind(document.body)`
<${tag}></${tag}>
`

これはエラーです

wire を使えばこのようにすることは可能です

bind(document.body)`
${
tag === "div" ? wire()`<div></div>` : ""
}
`

// or

const tags = {
div: () => wire()`<div></div>`,
span: () => wire()`<span></span>`,
}
bind(document.body)`
${tags[tag]()}
`

複数になるなら下のようにしたほうがテンプレートストリング中がスッキリします
ただどっちも事前に書いておく必要があって どういうタグが来るか不明の場合には対応できません
カスタムエレメントがあると名前は自由につけれますからね

タグ名に何が来るかわからない場合

wire はテンプレートストリングのタグ機能(HTML のタグじゃない)を使っているので見やすくないですが通常の関数呼び出しにすれば div や span のところに自由に文字列を設定できます

const w = wire()([`<${tag}></${tag}>`])

bind(document.body)`
${w}
`

この方法を使うと 埋め込んだタグ名は動的な部分にならないので変更時のチェックは行われません
普通に hyperHTML を使ったときにリテラルとして固定されてる文字列の部分になります
しかし wire が参照を持っていないので 部分的な変更じゃなく毎回新規作成したものに置き換えられます
再 render 時には wire のパーツ全体が置き換わるのでタグが変更できます

部分的な変更じゃなく全体を毎回置き換えは無駄に見えますが タグの変更なら普通に DOM 操作でやっても置き換えるしか無いです
タグの変更がないときには何もしないとか タグを変えたい要素だけ置き換えて子要素は同じものを使い回すとかは DOM を直接操作するならできます
しかし これに限らず hyperHTML などの便利なツール使うとか自分で DOM を完全にコントロールするのほど最適化はできないものと諦めてます

通常の埋込機能も使う

テンプレートストリングの埋め込み機能も使うならもう少し複雑になります

const tag = "custom-elem"
const tagid = "cc"
const h1id = "aa"
const h1text = "h1"
const spantext = "SPAN"

const w1 = wire()`
<h1 id="${h1id}">${h1text}</h1>
<span>${spantext}</span>
`
const w2 = wire()([`<${tag} id="`, `">`, `</${tag}>`], tagid, w1)

bind(document.body)`
${w2}
`

<body><custom-elem id="cc"><h1 id="aa">h1<!---0.380853%--></h1><span>SPAN<!---0.380853%--></span><!---0.380853%--></custom-elem><!---0.380853%--></body>

タグの内側の要素も直接関数呼び出しで作るのは大変なので別で普通に wire を使って作ったパーツを埋め込むようにしています
hyperHTML というよりテンプレートストリングの使い方になるので省略しますが w2 に代入している wire みたいに ${} の部分で配列を分割することになります

wwire

直接関数呼び出しで できはしたものの 見ての通り 複雑でわかりづらいです
これはシンプルな例なのでマシですが 実際に使うようなものをこういう記法で書くのはあまりやりたくないです

そこで こういうのを内部でやってくれる関数を用意しました

import {bind, wire} from "https://cdn.jsdelivr.net/npm/hyperhtml@2.25.5/esm.js"

const symbol = Symbol()

const wwire = ref => (tpls, ...values) => {
const [first, ...after] = tpls
const ntpls = [first]
const nvalues = []
for (const [index, tpl] of after.entries()) {
const value = values[index]
if (value && value[symbol]) {
ntpls.push(tpl)
nvalues.push(value[symbol])
} else {
ntpls[ntpls.length - 1] += String(value) + tpl
}
}
return wire(ref)(ntpls, ...nvalues)
}

const w = value => {
return { [symbol]: value }
}

wire の代わりに wwire を使います
wwire では ${} で埋め込むときに普通に埋め込むと リテラルと同じ扱いで埋め込みます
テンプレートの一部として扱われ この関数で作ったパーツ自体が置き換えられない限り変更されません
埋め込み時に w 関数を通すと hyperHTML としての埋め込みになります

const values = {tag: "div", id:"aa"}

const w1 = wwire(values)`
<${values.tag} id="${w(values.id)}">${100}</${values.tag}>
`
bind(document.body)`${w1}`

複雑なことをしない

関数準備したり複雑なことをせずとも ${} の中には HTML 要素を入れることもできます

単純なものなら こういう使い方のほうがいいかもしれません

const tag = "div"

const elem = document.createElement(tag)
bind(elem)`
<span></span>
`

bind(document.body)`
${elem}
`