<details name> による排他的アコーディオンの実現

<details> 要素に name 属性が追加され、グループ化が行えるようになりました。Open UI での議論を発端としたもののようです。

これは <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 が対応しており、動作を確認することが可能です。

<details name> による排他的アコーディオンの動作デモ(Chrome canary 117)

複数の 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 仕様では以下のように規定されています。

A document must not contain more than one details element in the same details name group that has the open attribute present. Authors must not use script to add details elements to a document in a way that would cause a details name group to have more than one details element with the open attribute present.

4.11.1 The details element(WHATWG)

一方、Open UI のページには以下のような記述があります。

Enforce exclusivity only for user interactions, use of the open IDL attribute, or setting the open attribute via setAttribute (or setAttributeNS, setAttributeNode, or setAttributeNodeNS). Do not enforce exclusivity when the open attribute is set by the parser, when it is set as a result of cloning a node, or when an element is moved to a new document. Do not enforce exclusivity for elements whose root is not a Document or a ShadowRoot.

Interaction with open attribute(open-ui.org)

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, ...(W3C)
HTML4 HTML 3.2 と同じ。RFC 1866 の定義から変更された理由として、ユーザエージェントの実際の挙動を考慮した結果であることが明記された。 17.2.1 Control types(W3C)
W3C HTML5, HTML LS ひとつも checked 属性がない状態が許容されるようになった。RFC 1866 と異なり、ユーザーエージェントの初期表示でもいずれもチェックされないものとされた。 4.10.5.1.16 Radio Button state (type=radio)(WHATWG)

仮に <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 仕様はこのように書かれています。

The group of elements that is created by a common name attribute is exclusive, meaning that at most one of the details elements can be open at once. While this exclusivity is enforced by user agents, the resulting enforcement immediately changes the open attributes in the markup. This requirement on authors forbids such misleading markup.

4.11.1 The details element(WHATWG)

印刷時の考慮

§

Web ページの画面上では排他的アコーディオンの挙動で良くても、印刷時には複数ないしすべてを展開したいかもしれません。これについても Open UI で議論があったものの、現時点では印刷時の強制展開といった処置はしない結論になったようです。(HTML 仕様には印刷時のことは何も書かれていません)

ブラウザが何もしないにせよ、ページ制作者が JavaScript で beforeprint, afterprint イベントを検知し、一時的に name 属性を除去して排他的でなくすことによって制御することは可能でしょうが、そうしてしまうと逆に展開が必要ないユーザーによっては望んだ結果にはならず、また分量によっては用紙とインクの無駄遣いにもなりかねないため、明らかに全展開が望ましい場合以外は慎重になるべきでしょう。