💡
2024/02/29 現在の情報になります。
はじめに
Reactに慣れてきた頃、WebComponentsを使う機会がありました。
Reactだと書けるが、WebComponentsでは書けないことがあり、ハマったので記事にしてみます。
ハマったところ
select
をコンポーネントにしてみます。
Reactの場合
MUIを参考にしてみます。
select
のコンポーネントと言えば、こんな感じですよね。
WebComponentsで実装した場合
MUIのように理想としては以下のように作りたいところです。
では作成してみましょう。
まずはWebComponentsのおさらいですが、以下のようにすれば div
で囲って slot
が入るだけのコンポーネントを作れます。
上に従って x-select
と x-option
を作ってみましょう。
実際に動かしてみます。
何故 slot
の中に、何も入らなかったのでしょうか?
一応 x-option
を使わずに実行してみます。
これも slot
の部分に、何も入っていないことが分かります。何故でしょうか?
これはWebComponentsの仕様が関係しています。
子に <slot/>
を持てる要素は attachShadow()
が使える要素に限るのです。
使用できる要素の一覧は以下で確認できます。ここに select
が含まれていないことが分かります。
Customized built-in elementの場合
先ほどの例は、自立カスタム要素(Autonomous custom element)で実装したものでした。
では、カスタマイズされた組み込み要素(Customized built-in element)ではどうでしょうか?
コードを以下のように変えてみます。
実際に動かしてみると、JavaScriptのエラーが発生しました。
この原因も先ほどと同じです。
 select
や option
は attachShadow()
が出来ないので、このような実装をする事が出来ないのです。
Declarative Shadow DOMの場合
最近モダンブラウザで使えるようになった、 Declarative Shadow DOM もせっかくなので試してみましょう。
がっ……駄目っ……! 理由はやはり同じです。
結論
WebComponentsでは、React(MUI)のような書き方が出来ないことが分かりました。
ではどうするのか
Vue.jsを思い出してみてください。Vuetifyの Select
では以下のような書き方をします。
このように属性(Props)を使うような書き方をすれば、WebComponentsでもそれらしい事が出来ます。
JavaScriptで属性を確認して、 option
をShadowDOM内に生成するようにします。
こちらでも、課題はいくつかあります。
課題1 何を入れたら良いのか直感的に分かりづらい
今回はitemsの中身に配列(JSON)を入れていますが、これは実装者によるため予想不能です。
属性名がvalueかもしれませんし、 options
かもしれません。
配列じゃなくて、CSV形式( California, Colorado, ...
)かもしれません。
そのため、チームで統一するようにするか、コンポーネントを使う度にドキュメントを見直す事になります。
課題2 破壊的変更になりがち
select
には option
以外にも、 optgroup
を使う事が出来ます。
それを運用中に実装するとなったら困ることになります。
例えばitemsを配列で実装していた場合は、ここで詰むことになります。
破壊的変更をするか、新しく optgroup
に対応した select
コンポーネントを作るかという二択になってしまいます。
JSONで option
か optgroup
が選択出来るように実装していた場合はラッキーですが、課題1の問題点明らかに出ていると思います。
課題3 読みづらい
これは個人的な感想ですが、Reactなどの書き方と比べると、分かりづらい書き方を強要されます。
Litなどのフレームワークを使えば多少マシになりますが、ReactやVue.jsで書きたくなること間違いなしです。
最後に
Reactと比較したWebComponentsの実装を本記事で書きました。
この問題はWebComponentsがあまり使われていない理由の一つになっていると思います。
attachShadow()
を使う事が出来る要素が増えれば解決するのですが、セキュリティ上の都合による理由など簡単には行かないようです。
それでも、WebComponentsのポテンシャルは無視できません。今後のアップデートに期待したいところです。