🎄Open UI Advent Calendar: Day 14 / Customizable Select Element Ep.12

2024-12-14

目次

目次

  1. はじめに
    1. part属性を使用することの問題
    2. Rename part to behavior
    3. 要素をCloneしてカスタマイズ可能にする<selectedcontent>の提案
    4. Appendix

はじめに

🎄 この記事はOpen UI Advent Calendarの14日目の記事です。

Ep.11では、<selectedcontent>とはどんな要素なのか、その契機となったIssueの紹介、part属性とslot属性についてお話ししました。

2024/12/9時点でのselectの各パーツの定義 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
[SELECT] The use of "part" clashes with custom elements containing <selectmenu> · Issue #354 · openui/open-ui
Copy/pasted from MicrosoftEdge/MSEdgeExplainers#483 so we can discuss/bikeshed names in OpenUI. @mfreed7 says: According to the explainer, here, when authors "replace" a part of the <selectmenu> us...
[SELECT] The use of "part" clashes with custom elements containing <selectmenu> · Issue #354 · openui/open-ui favicon https://github.com/openui/open-ui/issues/354#issuecomment-954161227
[SELECT] The use of "part" clashes with custom elements containing <selectmenu> · Issue #354 · openui/open-ui

最終的に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!

Appendix

Copyright © 2025 saku 🌸 All rights reserved.