🎄Open UI Advent Calendar: Day 13 / Customizable Select Element Ep.11
Published on
Updated on
Customizable Select Elementの関連仕様: `<selectedcontent>` - `<selectedcontent>`提案のきっかけと、選択された`<option>`のvalueとスタイルを反映する初期の仕組みとして、`part`属性と`slot`属性について
Table of Contents
Table of Contents
はじめに
Customizable Select Element Ep.8からEp.10まで、 appearance: base-select;で提供される、CSE のデフォルトの見た目が決定された背景をお話ししてきました。
今回からは、<selectedcontent>が、どうして仕様に入ることになったのか、どういった技術的背景があるのかをお話ししていきます。
2024/12/9時点でのselectの各パーツの定義
Customizable Select Elementの関連仕様
<selectedcontent>とは
<selectedcontent>は、現在選択されている<option>のテキストを含む要素です。ユーザーがオプションを選択するたびに、ブラウザは<selectedcontent>の子要素を、新しく選択された <option> で cloneNode() を呼び出した結果に置き換えます。
<selectedcontent> を使用すると、選択された <option> のコンテンツを宣言的にボタンに複製することができます。これによって、<selectedcontent>内には、<option>内部コンテンツとは別のスタイリング・DOM 操作を適用できます。
次の使用例では、<selectedcontent>内のコンテンツに、<option>内部コンテンツとは異なる方法のスタイリングを適用しています。
<select>
<button>
selected option: <selectedcontent></selectedcontent>
</button>
<option><img src="https://www.ghibli.jp/gallery/thumb-ponyo021.png" alt="icon">Ponyo one</option>
<option><img src="https://www.ghibli.jp/gallery/thumb-ponyo042.png" alt="icon">Ponyo two</option>
</select>
select {
&::picker(select) {
appearance: base-select;
}
selectedcontent {
.label {
display: none;
}
}
img {
width: 80px;
}
}
selectedcontent内部に、選択したoptionの要素がクローンされている。selectecontent内部のオプションは画像だけを表示する
こうした、「DOM をクローンして、別の DOM の内部要素として挿入し、レンダリングする」という仕組みを提供する HTML 要素は、筆者の調査範囲では、<selectedcontent>が初めての仕様となります。
そもそも現在の<select>には「選択された<option>内のコンテンツを<button>に表示する」という仕様すらないのですが、どうして CSE を実現する上で<selectedcontent>が必要となり、仕様策定されることになったのでしょうか?
<selectedcontent>の背景
<selectedcontent>のきっかけとなった提案は、もともと「[select]Inconsistent CSS handling when the “selected” attribute has been set on an option ?」というタイトルで 2022 年に登録された次の Issue でした。
この Issue の当初の期待としては、「選択された<option>のスタイルが、<select>自体のスタイルよりも優先されて表示されるようにするべき」というものでした。
具体的には、次のような場合に、選択された<option>のスタイルを<select>にも反映すべきではないか、ということです。
選択された要素のスタイルがボタン部分に反映されない
現状の<select>では、<select>が閉じた状態(つまり、選択肢が表示されていない状態)では、<option>のスタイルが<select>に直接反映されることはありません。これは、<select>要素の基本スタイリングが UA に任されており、<select>と<option>は異なる要素であるためです。
選択されたオプションのスタイルを<select>要素に反映させるとなると、JavaScript を使って命令的にスタイルを変更する必要があります。
実は、当時<selectmenu>(CSE の前身)が提案されていた段階では、<selectmenu>の内部に選択された<option>のスタイルを反映する仕組みが提案されていました。
それがbehavior属性とslot属性であり、その前身としてpart属性とslot属性の利用が提案がありました。
part属性とslot属性
MS で CSE の初期 Explainer が提案された時代、<select>コントロール(現 Anatomy では<button>の部分)をカスタマイズするために、part属性とslot属性を使用することが提案されていました。
part属性は Shadow DOM の仕様であり、::part()は CSS Shadow Parts として既に提案されています。
また、slot属性も Shadow DOM の仕様であり、今回特に新しく定義されたものというわけではありません。
端的にいうと、part属性は Shadow DOM にスタイルを適用するための属性で、::part()を使用して、Shadow DOM にスタイルを適用することができます。
また、slot属性は Shadow Root 内の特定の<slot>に、特定の Light DOM を挿入するための手法です。
上記 MS Explainer の<selectmenu>を例にとると、slot属性を使用して、<selectmenu>内の<slot name="button">に、<div slot="button">を挿入することができます。
そして、::part()を用いて、<selectmenu>内の<slot name="button">にスタイルを適用することができます。
<selectmenu>
<div slot="button" part="button">Custom button</div>
<option>Cat</option>
<option>Dog</option>
</selectmenu>
<!-- selectmenuのShadow DOMマークアップのイメージ -->
<template shadowrootmode="open">
<slot name="button"><!-- ここにslot="button" part="button"を持つdivが入って、カスタマイズ可能なコントロールとして振る舞う --></slot>
<!-- option -->
</template>
しかし、このpart属性とslot属性を使用する仕様には問題がありました。
それでは、また明日⛄
See you tomorrow!