isの課題と代替案 - カスタム組み込み要素
Web Components
今回から3回に渡り、カスタム組み込み要素(customized built-in elements)について書いていきます。
カスタム組み込み要素とは #
一部ブラウザでis属性を用いて、標準のHTML要素を拡張したカスタム要素を作ることができる機能です。
例えば以下のようにJSとHTMLを書くと、word-countというカスタム組み込み要素を定義して利用することができます。
// HTMLParagraphElementをextendsすることに注意
class WordCount extends HTMLParagraphElement {
constructor() {
super();
// いろんな処理
}
}
customElements.define("word-count", WordCount, { extends: "p" });
<p is="word-count"></p>
こうすることで、<p>要素の動作やセマンティクスを継承しながらカスタム要素を作成することができます。
他の要素だと例えば<button>であればtype="submit"やtype="reset"などの機能を使うことができたり、比較的新しい機能であるpopovertargetやcommandfor、interestforなどの属性をカスタム要素に対して指定できるようになります。また、<label>のfor属性なども同様です。
今までも1つ1つ明示的に属性の同期処理などをJSで書けば可能でしたが、カスタム組み込み要素では拡張している要素の動作やセマンティクスを全て一括で継承できるところがポイントです。
また、この書き方であればJSを読み込んでいないときでもis属性を無視すれば処理を追加していないただの拡張元の標準HTML要素として扱うことができるという点もメリットの1つとして挙げられています。
読む https://github.com/WICG/webcomponents/blob/gh-pages/proposals/Type-Extensions.md
isを用いたカスタム組み込み要素の問題点 #
isを用いたカスタム組み込み要素にはいくつか問題点があり、Webkitではopposedなpositionが取られてきています。
主に以下の問題点が挙げられます。
- shadow tree が attach できなかった
HTMLHeadingElementが全部の level をまとめていたり、<input>の type を指定できない- 3 回同じようなことを書く必要がある
- https://github.com/WICG/webcomponents/issues/509#issuecomment-222860736
- local name はカスタム要素の名前?
- https://github.com/WICG/webcomponents/issues/509#issuecomment-230700060
- 親クラスに機能が追加されたときに、サブクラスでもサポートしないといけなくなる
<custom-element>の場合と<a is="custom-element">の場合が混在して読みづらい
https://github.com/WebKit/standards-positions/issues/97 https://github.com/w3c/tpac2023-breakouts/issues/44 https://bugs.webkit.org/show_bug.cgi
これらを踏まえて、様々な代替案が検討されてきました。今回は1つ紹介します。
Custom Attributes #
Custom Property + 0 or more Custom Attributes => Custom Enhancement · Issue #1000 · WICG/webcomponentsやlume/custom-attributes: Define custom attributes that provide mixins for HTML elements、lume/element-behaviors: An entity-component system for HTML elements.を基にしてTPAC2023のbreakoutsで議論された代替案です。その後、以下のissueでさらに話し合われました。
Custom Attributesとは、カスタム要素と同じようにカスタマイズされたHTML属性をclassを用いて作成する機能です。これをHTML要素やカスタム要素に適用し、独自の動作を当てることができるようになるというものです。
例えば以下の例だと、Attributeclassを拡張してListAttributeというカスタム属性を作成し、<input>要素で利用できるようにしています。
class ListAttribute extends Attribute {
ownerElement; // element this is attached to
value; // current value
connectedCallback() {
/* ... */
}
disconnectedCallback() {
/* ... */
}
// Called whenever the attribute's value changes
changedCallback() {
/* ... */
}
static dataType = AttributeType.IDREF;
// Optional default value
static defaultValue = null;
}
HTMLInputElement.attributeRegistry.define("ac-list", ListAttribute);
今までのisではHTML要素を拡張してカスタム要素を作成し、カスタム要素に対して動作を割り当て、それをis属性に与えてしました。しかしそうではなく、HTML要素のattributeRegistryにカスタム属性を追加し、カスタム属性を通して動作を割り当てることができるようにするという提案です。
ユースケースとして
- Popover APIやInvoker Commandsのエミュレート
<time>にformat属性をつけ、指定したフォーマットで表示されるようにする<p loading-placeholder="3 sentences">のようなスケルトン表示<audio start-at="0:05">のような再生開始時刻の指定