目次
はじめに
Ep.11では、<selectedcontent>
とはどんな要素なのか、その契機となったIssueの紹介、part
属性とslot
属性についてお話ししました。
2024/12/9時点でのselectの各パーツの定義
part
属性を使用することの問題
Ep.11でも述べたように、<selectmenu>
内の<slot>
で置き換える要素をカスタマイズ可能にしたい場合、その要素にpart
属性を追加する必要があります。これは、::part()
を使用して、Shadow DOMにスタイルを適用するためです。
しかし、<selectmenu>
自体が別のShadow Rootにラップされていた場合はどうでしょうか?
Issueでは、例えば、<my-custom-select>
という別のCustom ElementのShadow Root内に<selectmenu>
がある場合、その中の<div slot="button" part="button">
が<my-custom-select>
の外部からスタイル適用される可能性があるとしています。
CSSでmy-custom-select::part(button)
というセレクタを使用すると、<my-custom-select>
のShadow Root内の要素へのスタイル適用を許してしまうことになります。
<my-custom-select>
<template shadowroot=open>
<selectmenu>
<div slot="button" part="button">Custom button</div>
<option>Cat</option>
<option>Dog</option>
</select>
</template>
</my-custom-select>
<style>
my-custom-select::part(button) {
/*This will match the button inside the custom element*/
background-color: red;
padding:20px;
}
</style>
この問題を解決するために、part
属性ではない別の属性名の立案が求められ、Open UI内での議論へ波及します。
Rename part
to behavior
Open UI内での議論では、以下のようなpart
の代替案となる属性名が提案されます。
- component
- subcomponents
- segments
- behavior
- controlpart
- componentpart
- controlsubpart
- controlledpart
- as
最終的にbehavior
属性が採用されることになり、WPTにも反映されることになります。
要素をCloneしてカスタマイズ可能にする<selectedcontent>
の提案
さて、ここまでで、<selectedcontent>
の背景で述べたIssue提案時の状態になりました。
Issueの期待は、「選択された<option>
のスタイルが、<select>
自体のスタイルよりも優先されて表示されるようにするべき」というものだったのに対し、behavior
属性とslot
属性を用いると、<selectmenu>
内の要素をカスタマイズ可能にすることができます。
その際に問題なのが、「選択された<option>
をどう<select>
自体のスタイルよりも優先させるか」つまり、「<option>
の内部をどう<select>
のボタンに持ってくるか」という部分でした。
仮に、「<option>
の内部」を「選択された<option>
のvalueのみ」というスコープに留めると、<option>
要素が選択された際に、<slot name="selected-value">
に、選択された<option>
のvalueを反映することでカスタマイズを可能にする、というワークアラウンドが考えられている、とGregは述べています。
<selectmenu>
<div slot="button">
<button behavior="button">Open</button>
<span behavior="selected-value" slot="selected-value"></span>
</div>
<option style="color: blue;">Option 1</option>
<option style="color: red;">Option 2</option>
<option style="color: green;">Option 3</option>
</selectmenu>
let s = document.querySelector('selectmenu');
let sv = document.querySelector('[behavior=selected-value]');
let possibleOptions = document.querySelectorAll('option');
s.addEventListener('change', () => {
possibleOptions.forEach((option) => {
if(option.value == s.value) {
sv.style.color = option.style.color;
}
});
});
しかし、上記は単なる限定的な範囲でのワークアラウンドに過ぎず、<select>
のボタン部分に反映できるのは、選択された<option>
のvalueのみです。
もともとこのIssueを出した人が、「選択された<option>
のスタイルが、<select>
自体のスタイルよりも優先されて表示されるようにするべき」の達成期待値をどこまで持っていたかは不明ですが、その時点での<selectmenu>
では、<option>
に任意のコンテンツ/スタイルを設定できるように仕様が固まりつつあったため、「<select>
のボタン部分には、選択された<option>
のvalueに限らず、<option>
内のコンテンツを反映できる方法を考えるべきか?」と、Gregから、Issueの返信として意見が募られます。
すべてのコンテンツを複製して反映するのか、複製するとしたらデフォルトなのか、オプトインなのか、それとも複製せずにvalueだけを反映するのか、このIssueを皮切りに議論が展開されていくことになります。
それでは、また明日⛄
See you tomorrow!