Customizable Select ElementにおけるParser RelaxationのアップデートとShipの背景

Published on

長年の議論を経て、ようやく仕様が固まった、CustomizableなSelect要素の現状について、Parser Relaxationのを軸に解説します

Table of Contents

Table of Contents

はじめに

<select>のスタイルや機能拡張を行うために、これまでに多くの関連機能が提案され、仕様策定され、実装されてきました。 その中でも特に、Customizable Select Element を実現する上で欠かせなかった、HTML Parser の緩和に関するバグが、後方互換性の心配が非常に低くなる程度に修正され、Ship のIntentが発表されました。

本エントリでは、今回の Intent に影響を与えた、Parser Relaxation について見ていきます。

Parser Relaxation

新しい<select>では、次のように、カスタムの<button>を設置したり、<option>の中に任意のタグを挿入したりすることができます。これによって、独自のボタンで::picker(選択肢のポップアップ)をトリガーしたり、<option>の中に<img>や任意のコンテンツを入れて、選択肢として表示することが可能になります。

<style>
select,
::picker(select) {
  appearance: base-select;
}
option::checkmark {
  display: none;
}
</style>
<select>
  <button>
    <selectedcontent></selectedcontent>
  </button>
  <option value="andorra">
    <img src="https://upload.wikimedia.org/wikipedia/commons/thumb/1/19/Flag_of_Andorra.svg/120px-Flag_of_Andorra.svg.png" alt="" />
    <span>Andorra</span>
  </option>
  ...
</select>

Country select with Flags Country select with Flags

しかし、現状の<select>では<option>, <optgroup>, <hr>のみを内部要素として許可しているため、これらの要素以外を含む<select>がうまくパースされるよう、<select>の Content Model を変更し、それに応じて HTML パーサに変更を加える必要があります。

Content model: Zero or more option, optgroup, hr, and script-supporting elements. https://html.spec.whatwg.org/multipage/form-elements.html#the-select-element

Parser RelaxationはChrome 131でShipされていた

この Parser Relaxation は、Chrome 131 で Ship の Intent が出ており、実際に Chrome 131 で Ship されていました。

この時点では、パーサの変更による既存の<select>との後方互換性が懸念されていたため、まず一度 Parser Relaxation を Ship してみて、ユーザからのフィードバックを受けつつ、適切な対処がされるというモチベーションでした。

This change is in support of the customizable <select> feature but is being shipped first because it can be done separately and has some compat risk which I’d like to get feedback on. … If there are major issues with this change, I will reassess and make adjustments to the parser as needed.

Parser Relaxation無効化の背景

Chrome 131 で Ship 後、選択肢ドロップダウンが正常に動作しない問題が複数報告されます。

このバグは、<option><div>など任意の HTML 要素の子要素となっていた場合、ドロップダウンが開かないというものでした。

Basically if options inside select element are wrapped in other HTML tag like astro-slot (Astro/SolidJS setup) or even a simple DIV, dropdown does not open. Reproducible only on Chrome 131, after this https://chromestatus.com/feature/5145948356083712

ref: https://issues.chromium.org/issues/379034733#comment10

この問題は、Parser Relaxation の変更によって発生したものであることが判明し、Chrome 131, 132 で Parser Relaxation を無効化することで対応されました。

I disabled this new parser behavior in chrome 131 due to a bug with one of multiple code paths which collects options to render in the select’s popup which doesn’t exist in the spec. …

I think it makes sense to wait with merging this PR until it has been shipping in Stable for a bit.

That sounds reasonable to me especially since shipping this change in chrome is not blocked by merging this PR.

ref: https://github.com/whatwg/html/pull/10557#issuecomment-2515300782

Parser Relaxationの有効化

一時は無効化された機能でしたが、上記のバグは以下で修正され、これまでに、Parser Relaxation によるその他リグレッションのほとんども解消されてきました。

Chrome 133 からは Parser Relaxation は Finch されており、その他 Customizable Select Element 関連の実装も Chrome 134 で Ship されることに繋がります。

そのほかの懸念

Relaxation 以前のパーサの挙動では動作していた<select /> <input />といった書き方が、Parser Relaxation によって動作しなくなるという懸念は、現時点でも依然として残るようです。

たとえば、次のような HTML で、<input>がレンダーされる/されないという挙動の違いが確認されています。

<select></select> <input />

<hr />

<select /> <input />

Experimental Web Platform features enabled

Chrome Canary 134Chrome 131
Chrome Canary 134Chrome 131

これに関しては、専用のフラグが用意されているため、もしロールアウトして問題があっても、Chrome のリリースを伴わずに機能を無効にすることができます。


数多くの構文と動作変更を繰り返してきた Customizable Select Element の Ship は、Joey Arharによる、辛抱強い繰り返しの実装の末に実現されています。

Web の開発体験を大きく変えるたくさんの機能の実現にも貢献してきた、Customizable Select Element。長年実現が待ち望まれていた新しい機能のリリースなだけ、とてもワクワクさせられます🎉