フロントエンドの現場で一番よく聞く愚痴。
「このボタン、押したらポップオーバーを出すだけなのに、JSが50行ある」。
分かります。分かり過ぎる。
そしてその50行が、いつの間にか100行になり、レビューで突っ込まれ、アクセシビリティ対応で更に増え、最後は「触るな危険」の神殿になる。あるあるです。
そこで出てきたのが、HTMLだけでUIの操作をかなり宣言的に書ける流れ。
具体的には command / commandfor、そして interestfor です。Open UIの提案として整理され、PopoverやDialogなど既存のプラットフォーム機能と噛み合う形で進んでいます。
この記事は「JSをゼロにしよう」みたいな宗教ではありません。
ただ、雑に増えたJSを一度やめて、HTMLで出来るところはHTMLに返す。その方が速い、壊れにくい、そして保守が楽。そういう話です。
まずは前提: 何をやめる話なのか
やめる対象は「UIの基本動作のためだけに書く手作りJS」です。
トグル、開閉、簡単な説明ポップ、ホバーで補足表示。こういう定番UIを全部JSで自前実装するやつ。
なぜ止めたいのか。理由はシンプルで、コストの割にリターンが薄いから。
たとえばポップオーバーひとつでも、クリック外で閉じる、Escで閉じる、フォーカストラップ、aria属性、スクロール追従、z-index地獄。これを毎回手で書くのは、わざわざ難しい方へ歩いている感があります。
しかもそのJS、だいたい「UIの仕様書」になっていない。
読む人にとっては挙動が分かりづらいし、HTML構造をちょっと変えただけで壊れる。嫌な壊れ方をします。
commandとcommandforって何者
commandfor は「このボタンは、どの要素に命令するのか」をIDで指す属性です。command は「どの命令を出すのか」を文字列で書きます。
雑に言うと、HTML版の「このボタン押したらあれ開く」を標準化しようとしている。
PopoverやDialogなど、ブラウザが挙動を知っている相手なら、JSなしで操作を成立させられる。そこが強い。
Popoverをcommandで開閉する
Popover自体は既にプラットフォーム側の機能として存在し、ボタンで開閉するにはこれまで popovertarget を使うのが基本でした。
提案されている commandfor は、その役割をより汎用の「invoker」方向へ寄せたものです。:contentReference[oaicite:2]{index=2}
<button type="button" commandfor="my-popover" command="toggle-popover">
Open Popover
</button>
<div id="my-popover" popover="auto">
Hello world
</div>
command="toggle-popover" は、閉じていれば表示、開いていれば非表示。show-popover、hide-popover のような命令も整理されています
Dialogもcommandで動く
Dialogは「モーダル実装の地獄」を減らすための救世主枠です。
そして command はDialogにも素直に効く。:contentReference[oaicite:4]{index=4}
<button type="button" commandfor="my-dialog" command="show-modal">
Open Dialog
</button>
<dialog id="my-dialog">
Hello world!
<button type="button" commandfor="my-dialog" command="close">Close</button>
</dialog>
ここで地味に嬉しいのが、プラットフォーム側がアクセシビリティ面のマッピングも考慮している点です。
Popover系のcommandでは、状態に応じて支援技術向けの関連付けが考慮される設計が説明されています。:contentReference[oaicite:5]{index=5}
さて、あなたのプロジェクトにも「自作モーダルJS」が眠っていませんか。
眠っているどころか、起きて暴れてませんか。
interestforって何者
interestfor は「ホバーしたら出す」「注目している間だけ補足を見せる」みたいな、UIの“気配”をHTMLで表現しようという発想です。
従来なら mouseenter / mouseleave を書いて、遅延を調整し、スマホでは挙動を変え、結局バグる。あの流れを軽くします。:contentReference[oaicite:6]{index=6}
hovercardをinterestforで作る
Popoverを“ヒント用途”として使う場合の例が提案されています。
<button interestfor="my-popover" type="button">
Hover for popover
</button>
<div id="my-popover" popover="hint">
Hello world
</div>
ここでのキモは、ユーザーが「興味を示している」間に出す、というモデル。
単なるホバーより、もう少し人間の操作感に寄せる余地がある。Open UIでは、interestが発生したり失われたりする時に InterestEvent が発火する仕様案も書かれています。
interestforはJSをゼロにしない。だが雑なJSを減らす
正直、ここは誤解が起きやすい。
「HTMLだけで何でも出来る」ではなく、「UIのきっかけをHTMLで宣言できる」方向です。
つまり、ホバーや注目の検出といった薄いロジックはプラットフォームに寄せられる。
一方で、見せる内容の生成、トラッキング、複雑な状態管理はJSの出番。住み分けが美しい。
commandとinterestforでJSを減らすと何が嬉しいのか
ここからは完全に私の偏見。
現場で刺さるポイントだけ並べます。
保守: 「クリックしたら開く」がHTMLから読める
ボタンを見たら、commandfor と command が書いてある。
読んだ瞬間に挙動が分かる。JSを探す必要がない。これが一番でかい。
アクセシビリティ: 後付けのariaより、最初から整える方が安い
PopoverやDialogのようなプラットフォーム機能は、アクセシビリティを無視できない設計になっています。
Invoker系の説明でも、支援技術との関連付けやフォーカス復帰などに触れています。
自作UIは、見た目は整っても支援技術で崩れがち。
後から直すコストが高い。ここが痛い。
パフォーマンス: JSの初期化コストが地味に減る
イベントリスナーをばら撒かない。初期化処理も減る。
小さな差に見えて、積み上げると効きます。
特にWordPress案件で「プラグイン由来JS + テーマJS + LP用JS」が合体した時、初期化が渋滞する。
その渋滞を少しでも減らしたいなら、UIの基本動作をHTMLに寄せる価値はあります。
やり方: 既存UIを置き換える現実的な手順
いきなり全部置き換えると事故ります。
現実の手順はだいたいこう。
Step1: まずPopoverかDialogから始める
既にプラットフォーム機能があり、価値も高い。
モーダルやツールチップの自作JSを消しやすい。
既存のボタンに commandfor を足して、対象要素に popover や dialog を使う。
挙動の差分が出るところだけ、最小限のJSで吸収します。
Step2: JSは「挙動を作る」から「状態を補助する」へ
自作UIの典型は、クリックを拾ってクラスを付けるやつ。
これを卒業して、commandやpopoverのイベントを受けてログを取る、アニメーションを足す、見せる内容を差し替える。そういう補助役に回す。
Step3: 段階的にinterestforへ
hovercardや補足表示は、UIの好みが分かれる領域です。
また、タッチデバイス対応も絡むので、いきなり全面採用より「一部だけ」で様子を見るのが現実的。
Open UIの説明では、interestが発生した時と失われた時に InterestEvent が発火し、source で発生元も取れる設計が示されています。これがあると、後から挙動の微調整がしやすい。
メリットだけじゃない: デメリットもちゃんとある
ブラウザ対応: 最初は割り切りが必要
これらは比較的新しい領域で、提案や実装状況が動く可能性があります。
だからこそ、今やるなら「プログレッシブエンハンスメント」が前提になります。
対応しているブラウザではHTMLでスマートに動く。
対応していないブラウザでは、従来のJSフォールバックを使う。これでよい。
設計が雑だと「HTMLに書いたのに壊れる」になる
commandfor はID参照です。
IDが重複したら終わり。テンプレートが増殖するWPでは特に注意。
コンポーネント化してIDをスコープ化する、生成規則を決める、そもそもDOMに同名IDを出さない。
当たり前の話が当たり前に大事になる。
カスタムコマンドは万能ではない
Invokerの説明では、command にダブルダッシュを含めたカスタム命令を使うと、対象要素に command イベントを飛ばせる例が書かれています。:contentReference[oaicite:11]{index=11}
ただし、これを乱用すると「HTMLに書いたカスタムイベント駆動JS」という別の沼が生まれる。
便利だからこそ節度がいる。
実務で刺さる: こういうUIを置き換えると効果が出る
ヘッダーのメガメニューの補足
メガメニューの説明文、注意書き、キャンペーンの注釈。
hovercardとして出すだけなのに、JSが増えがちです。
ここをPopover + interestforで整理すると、挙動の核がHTMLに寄ります。
JSは「出す内容をCMSから差し込む」「表示遅延を調整する」くらいに縮む。
フォームの補足説明
入力例、注意点、プライバシーの補足。
フォームはアクセシビリティで火傷しやすい場所です。
Popoverを素直に使い、commandで開閉を宣言すると、余計なクリック外検知スクリプトが消えます。
無駄に重いフォームが、ちょっとだけ健康になる。
管理画面のミニダイアログ
WordPress管理画面っぽいUIでも、Dialogは便利。
confirm代わりの軽いモーダルを自作しているなら、置き換えの価値は高い。
ハマりどころ集: 先回りして潰す
「閉じる」導線を必ず用意する
Popoverは出せると気持ちいい。
でも閉じられないと地獄。特にキーボード操作。
commandで hide-popover を用意するか、Popover内に閉じるボタンを置く。
人間は親切に甘える生き物です。
「ホバー前提」は捨てる
interestforはホバーだけの話ではなく、「興味」を扱うモデルですが、実装やデザインがホバー偏重だと破綻します。
タッチ端末、ペン入力、キーボード。世界は広い。
ここ、あなたのサイトはスマホで触られてますよね。
ホバーだけで補足を出して満足していませんか。
計測と相性が良い
UIイベントをJSで作ると、計測イベントが散らばる。
HTMLに宣言があると「このcommandが押された」を一箇所で拾いやすい。
Open UIの設計では、interest / loseinterest のようなイベントのモデルも示されています。計測との相性はかなり良い。:contentReference[oaicite:12]{index=12}
関連知識: この記事と一緒に押さえると強い
Popover APIを触っておく
commandやinterestforは、Popoverと組むと旨味が増えます。
Popoverの基本概念(表示モード、位置決め、閉じ方)を理解しておくと、実装判断が速くなる。
Dialog要素の癖も知っておく
showModalやclose、フォーカスの戻し方。
Invokerの説明でも、Dialogを開いたボタンへフォーカスを戻す考慮が語られています。:contentReference[oaicite:13]{index=13}
プログレッシブエンハンスメントの型
対応ブラウザではHTMLで動く。非対応ではJSで補う。
この二段構えを当たり前にするだけで、最新機能を怖がらずに使えます。
最後に: 私のこだわりを言い切る
UIの基本動作は、出来るだけプラットフォームに寄せた方がいい。
フロントエンドは、勝ち筋がある場所に脳みそを使うべきです。
ボタンを押したら開く。ホバーしたら補足が出る。
そんな定番動作に、毎回同じバグを作り、毎回同じレビュー指摘を受けるのは、さすがにやめたい。
commandとinterestforは、その「やめたい」をHTML側から助ける道具になり得ます。
流行りだから採用するのではなく、コードベースの脂肪を落とすために使う。私はその使い方が好きだし、現場でも効くはずだと見ています。
