🎄Open UI Advent Calendar: Day 14 / Customizable Select Element Ep.12
Published on
Updated on
Customizable Select Elementの関連仕様: `<selectedcontent>` - `part`属性をCSEのUA実装で使用することの問題から、`part`属性を`behavior`属性にリネームへ。`<option>`のvalueのみならず、内部コンテンツ自体を`<selectedcontent>`に反映する仕様策定の示唆
Table of Contents
Table of Contents
はじめに
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!