<details name>
による排他的アコーディオンの実現
<details>
要素に name
属性が追加され、グループ化が行えるようになりました。Open UI での議論を発端としたもののようです。
-
4.11.1 The
details
element - Add name attribute for grouping details elements into an exclusive accordion by dbaron · Pull Request #9400 · whatwg/html
- Exclusive Accordion (Explainer)(
open-ui.org
)
これは <details>
要素を開いた際に、すでに開いている他の <details>
要素を自動的に閉じる「排他的アコーディオン」を実現するものです。使い方としてはラジオボタンと同じく、グループ化したい <details>
要素に同じ name
属性値を指定します。
<section>
<h2>フレームの特徴</h2>
<details name="frame-characteristics">
<summary>材料</summary>
<p>材料は...</p>
</details>
<details name="frame-characteristics">
<summary>サイズ</summary>
<p>サイズは...</p>
</details>
</section>
ブラウザの実装としては現在 Chrome canary が対応しており、動作を確認することが可能です。
複数の open
属性の設定
HTML に直接 open
属性が書かれた場合
「排他的アコーディオン」なので、複数の名前付き <details>
要素に open
属性を設定することはできません。
<!-- これは NG な事例です -->
<section>
<h2>フレームの特徴</h2>
<details name="frame-characteristics" open="">
<summary>材料</summary>
<p>材料は...</p>
</details>
<!-- ↓ `open` 属性が指定されているが、実際は開かれない -->
<details name="frame-characteristics" open="">
<summary>サイズ</summary>
<p>サイズは...</p>
</details>
</section>
実際に Chrome canary で試すとグループの最初のメンバーのみ開かれ、他のメンバーは(open
属性が指定されているにも関わらず)閉じられた状態になります。HTML 仕様では以下のように規定されています。
一方、Open UI のページには以下のような記述があります。
Open UI の方では複数の open
属性が許可されていたのですが、この場合はすべてのアコーディオンが開くものの、そのいずれかを一度閉じると、もはや元の状態(複数が開いた状態)には戻せないということになります。これははるか昔から checked
属性のないラジオボタングループで見られる挙動と同じく、非可逆な性質を持つものとなります。
<!--
`checked` 属性のないラジオボタングループの例
初期表示ではいずれも選択されていないが、一度どれかを選択すると「何も選択していない状態」には戻せない
-->
<p role="radiogroup">
<label><input type="radio" name="lang" value="ja" /> 日本語</label>
<label><input type="radio" name="lang" value="en" /> 英語</label>
<label><input type="radio" name="lang" value="po" /> ポロロッカ語</label>
</p>
参考までにラジオボタングループにひとつも checked
属性がない場合について、仕様の歴史を紐解くと次のような変遷を辿っています。
HTML バージョン | 仕様の記載 | 仕様へのリンク |
---|---|---|
HTML 2.0 (RFC 1866) | 最初のラジオボタンを on とする扱いとされた。ただし当時のユーザーエージェントは必ずしもこれに従わなかった。 |
8.1.2.4. Radio Button: INPUT TYPE=RADIO(datatracker.ietf.org ) |
HTML 3.2 | 必ず一つ checked 属性を書く必要がある。 |
INPUT text fields, radio buttons, check boxes, ... |
HTML4 | HTML 3.2 と同じ。RFC 1866 の定義から変更された理由として、ユーザエージェントの実際の挙動を考慮した結果であることが明記された。 | 17.2.1 Control types |
W3C HTML5, HTML LS | ひとつも checked 属性がない状態が許容されるようになった。RFC 1866 と異なり、ユーザーエージェントの初期表示でもいずれもチェックされないものとされた。 |
4.10.5.1.16 Radio Button state (type=radio )
|
仮に <details name>
も非可逆性を持った場合、ベストプラクティスの観点から議論を呼び起こし、ラジオボタンの歴史のように仕様がコロコロ変わったり、仕様とブラウザ実装が乖離したりする可能性が考えられたことから、HTML 仕様では当初から非可逆性が排除されて一安心といったところでしょう。
JavaScript から動的に open
属性が設定された場合
一方、以下のように JavaScript から open
属性を変更した場合、最後に操作された一つのみが開いた状態となります。
<script type="module">
for (const detailsElement of document.querySelectorAll('details')) {
await new Promise((resolve) => setTimeout(resolve, 1000)); // 動作状況を分かりやすくするため1秒間待機する
detailsElement.open = true;
}
</script>
<section>
<h2>フレームの特徴</h2>
<!-- ↓ 一度開かれる(`open` 属性が設定される)が、すぐに閉じられる(1秒後に `open` 属性が除去される) -->
<details name="frame-characteristics">
<summary>材料</summary>
<p>材料は...</p>
</details>
<!-- ↓ 最終的にこちらのみが開かれる(1秒後に `open` 属性が設定される) -->
<details name="frame-characteristics">
<summary>サイズ</summary>
<p>サイズは...</p>
</details>
</section>
HTML 仕様はこのように書かれています。
印刷時の考慮
Web ページの画面上では排他的アコーディオンの挙動で良くても、印刷時には複数ないしすべてを展開したいかもしれません。これについても Open UI で議論があったものの、現時点では印刷時の強制展開といった処置はしない結論になったようです。(HTML 仕様には印刷時のことは何も書かれていません)
ブラウザが何もしないにせよ、ページ制作者が JavaScript で beforeprint
, afterprint
イベントを検知し、一時的に name
属性を除去して排他的でなくすことによって制御することは可能でしょうが、そうしてしまうと逆に展開が必要ないユーザーによっては望んだ結果にはならず、また分量によっては用紙とインクの無駄遣いにもなりかねないため、明らかに全展開が望ましい場合以外は慎重になるべきでしょう。