アコーディオンのイラスト

`<details>` 要素の `name` 属性による排他的なアコーディオンの実装

`<details>` 要素の `name` 属性を利用してグループ化することにより、排他的なアコーディオンを JavaScript なしで実装できます。

Note

<details> 要素の name 属性は 2023 年 10 月 8 日現在 Chrome Canary のみ実装されています。

アコーディオンは Disclosure(コンテンツを折りたたむ、または展開することを可能にするウィジェット)が垂直に並べられた UI の総称です。いくつかのアコーディオンはグループ化された Disclosure の中でただ 1 つしか開くことができないという制約を持っています(排他的なアコーディオン)。つまり、ある Disclosure が開いているときに、他の Disclosure を開いた場合には、開いている Disclosure は閉じられるという挙動を実装する必要があります。

単純な Disclosure の場合には <details> 要素を利用することで JavaScript を用いずとも実装できます。しかし、排他的なアコーディオンを実装する場合には、他の Disclosure が開いているかどうかの状態を保持する必要があるため、JavaScript を用いた実装が必要でした。

ですが、HTML Living Standard に追加された name 属性を利用して <details> 要素をグループ化することによって、JavaScript を用いずとも排他的なアコーディオンを実装できるようになりました。

<details> 要素の name 属性を利用した排他的アコーディオンの実装

それでは実際に <details> 要素の name 属性を利用して排他的なアコーディオンを実装してみましょう。ラジオボタンと同じように、グループ化したい <details> 要素に同じ name 属性を設定します。HTML Living Standard によれば、<details> 要素をグループ化する場合には <section> 要素のような包含要素でまとめることが推奨されています。

<section>
  <details name="accordion">
    <summary>Accordion 1</summary>
    <p>Content 1</p>
  </details>
  <details name="accordion">
    <summary>Accordion 2</summary>
    <p>Content 2</p>
  </details>
  <details name="accordion">
    <summary>Accordion 3</summary>
    <p>Content 3</p>
  </details>
</section>

上記のコードは Chrome Canary で動作を確認できます。

JavaScript から open 属性を設定した場合

グループ化された <details> 要素の中で、JavaScript から open 属性を設定した場合には、他の <details> 要素の open 属性は自動的に false に設定されます。以下の例を見てみましょう。初期状態では 1 つ目の <details> 要素に open 属性が設定されて開かれています。

<section>
  <details name="accordion" open id="accordion1">
    <summary>Accordion 1</summary>
    <p>Content 1</p>
  </details>
  <details name="accordion" id="accordion2">
    <summary>Accordion 2</summary>
    <p>Content 2</p>
  </details>
  <details name="accordion" id="accordion3">
    <summary>Accordion 3</summary>
    <p>Content 3</p>
  </details>
</section>
 
<button>Open Accordion 2</button>

次のスクリプトは、ボタンをクリックした時、2 つ目の <details> 要素に open 属性を設定します。

const button = document.querySelector("button");
const accordion2 = document.querySelector("#accordion2");
 
button.addEventListener("click", () => {
  accordion2.setAttribute("open", "");
});

このコードを実行すると <details> 要素を直接操作した時と同様に、2 つ目の <details> 要素を開いたことによって、1 つ目の <details> 要素が閉じられることがわかります。

同じ <details> 要素のグループに複数の open 属性を設定した場合

HTML Living Standard によると、同じ <details> 要素のグループに複数の open 属性を設定してはならないと規定されています。

A document must not contain more than one details element in the same details name group that has the open attribute present.

実際に Chrome Canary で試してみると、2 つ目と 3 つ目の open 属性は無視され、1 つ目の <details> 要素のみが開かれます。

<section>
  <details name="accordion" open id="accordion1">
    <summary>Accordion 1</summary>
    <p>Content 1</p>
  </details>
  <details name="accordion" open id="accordion2">
    <summary>Accordion 2</summary>
    <p>Content 2</p>
  </details>
  <details name="accordion" open id="accordion3">
    <summary>Accordion 3</summary>
    <p>Content 3</p>
  </details>
</section>

参考


Contributors

> GitHub で修正を提案する
この記事をシェアする
はてなブックマークに追加

関連記事