記事を検索

details/summaryで実装するアコーディオン

アコーディオンUIは、限られたスペースに多くの情報を整理して表示できる便利なコンポーネントです。FAQページやサイドメニュー、設定画面など、さまざまな場面で活用されています。

昔はアコーディオンの開閉機能を実装するにはJavaScriptが必須でしたが、HTML5で導入されたdetailssummary要素を使えば、JavaScriptなしでアクセシブルなアコーディオンを実装できます。

このページでは、detailssummaryを用いたアコーディオンの構築方法を解説します。

details/summary要素についての基礎知識

details/summary要素には開閉機能がネイティブで備わっており、JavaScriptが必要ありません。 また、CSSでスタイリングしなくてもデフォルトで左側に三角形のマーカー(▶)が表示され、展開時には方向が変わる(▼)ようになっており、HTMLだけでも最低限の機能と見た目が担保されています。

まずはシンプルな例を見てみましょう。

HTML
<details>
<summary>クリックして詳細を表示できます</summary>
<p>ここに詳細な内容が入ります。</p>
</details>

summary要素は、details要素の最初の子要素として配置する必要があります。

このHTMLを書くだけで、以下のようになります。

Preview
クリックして詳細を表示できます

ここに詳細な内容が入ります。

details/summary を使うメリット

  • 開閉機能がネイティブで備わっている
  • Tabキーでフォーカス移動、Enter/Spaceキーで開閉が可能
  • スクリーンリーダー対応で、「折りたたみ」「展開済み」などの状態が自動的に通知される
  • ページ内テキスト検索時に、コンテンツが隠れていても自動で展開してくれる
  • name属性を使えば展開する要素を一つに制限してくれる

独自にdiv要素やbutton要素でアコーディオンを実装する場合、これらのアクセシビリティ対応を自前で実装する必要がありJavaScriptも必要になってきますが、details/summaryを使えばその手間が省けます。

summary内に見出しタグを配置した場合の問題点

summary内に見出しタグ(h1~h6)を配置した場合、スクリーンリーダーが見出しとして検出できなくなってしまうという問題があります。 これはsummaryが暗黙的にrole="button"扱いになっていることが原因のようで、アクセシビリティツリー上ではその中に配置されている見出しのロールを検出できません。

HTMLの仕様としては summary > hタグ の構造は許可されているものの、スクリーンリーダーでは正しく反映されない状況となっています。

VoiceOver読み上げ時にその「三角形の選択ボタン」の読み上げがいちいち入るのが邪魔な気がする(読み上げ対象から除外する方法がわからなかった)

[open]属性

details要素が開いている状態では、HTML上にopen属性が自動的に付与されます。これを属性セレクタで参照することで、開閉状態に応じたスタイルを適用できます。

details[open] {
/* details要素が開いている時のスタイル */
}

デフォルトの三角形マーカーを非表示にする方法

summary要素の三角形マーカーは、Chrome/Edge/Firefoxなどでは、summary要素のdisplayプロパティをlist-item以外に変更することで自動的に非表示になります。

Safariでは、::-webkit-details-markerという独自の疑似要素でこのマーカーがスタイリングされているため、以下のようにして明示的に非表示にするスタイルを書く必要があります。

summary::-webkit-details-marker {
display: none;
}

details/summaryで実装するアコーディオン

それでは、実際にdetailssummaryを使ってアコーディオンを実装してみましょう。

<div class="accordions">
	<details class="accordion">
		<summary class="accordion__title">
			<span>Q: 配送にはどのくらいかかりますか?</span>
		</summary>
		<div class="accordion__content">
			<p>ご注文から通常3〜5営業日でお届けします。お急ぎの場合は、お届け先や在庫状況により最短翌日配送も可能です。</p>
		</div>
	</details>

	<details class="accordion">
		<summary class="accordion__title">
			<span>Q: 返品・交換は可能ですか?</span>
		</summary>
		<div class="accordion__content">
			<p>商品到着後14日以内であれば、未開封・未使用に限り返品・交換を承ります。詳細は返品ポリシーをご確認ください。</p>
		</div>
	</details>

	<details class="accordion">
		<summary class="accordion__title">
			<span>Q: 支払い方法は何が使えますか?</span>
		</summary>
		<div class="accordion__content">
			<p>クレジットカード、銀行振込、コンビニ決済、各種電子マネー、代金引換がご利用いただけます。</p>
		</div>
	</details>
</div>

HTMLの構造はシンプルです。.accordionsというラッパー要素の中に、複数のdetails要素を配置しています。各details要素にはsummaryでタイトルを、その後に続く<div>でコンテンツを定義しています。

コンテンツの開閉アニメーションについて

アコーディオンUIを実装する際、コンテンツ部分の開閉にスムーズなスライドアニメーションを付けるケースがよくあります。
これまで、CSSだけではdetailsの開閉アニメーションを実装することは困難でした

従来の問題は次の2点。

  1. height: auto ではアニメーションができない。
  2. open属性が外れている時、コンテンツがレンダリングから完全に除外されてしまう。(display:none からフェードインできないのと同じ)

しかしながら、最新のCSSでは、CSSだけでもアニメーションが可能になりつつあります。

  • 1を解決するTips : grid-template-rows0fr~1frへトランジションさせるというテクニックがあります。また、将来的にはinterpolate-size: allow-keywords;を使うことでheight:autoのアニメーションが可能になります。
  • 2を解決するTips : ::details-content擬似要素を使うことで、コンテンツ用のslot要素に対してスタイルを付与することができるようになり、アニメーションも可能になりました。

interpolate-size, ::details-contentはまだブラウザ対応が完全ではないため積極的に導入はしずらいですが、将来的にはこれらを使ってCSSだけで開閉アニメーションを実装できるようになります。

ブラウザサポート状況(2025年12月時点)

interpolate-size Chrome 129 (2024/9)~ Firefox Safari
::details-content Chrome 131 (2024/11)~ Firefox 143 (2025/9)~ Safari 18.4 (2025/3)~

::details-contentは主要ブラウザで広くサポートされはじめていますが、interpolate-sizeはChromium系のみの対応となっています。非対応ブラウザではアニメーションなしで即座に開閉してしまいます。

CSSだけで開閉アニメーションを実装する例

::details-content に対して 0fr~1frのトランジションTispを使い、CSSだけで開閉アニメーションを実装する例を紹介します。 (interpolate-size: allow-keywords;を使ってheightをアニメーションさせた方が動きが滑らかな気がしたので、将来的にはそちらを使いたいですが、ひとまずサポート状況を優先しています。)

<div class="accordions">
	<details class="accordion" name="demo">
		<summary class="accordion__title">
			<span>Q: 配送にはどのくらいかかりますか?</span>
			<span class="accordion__icon" aria-hidden="true"></span>
		</summary>
		<div class="accordion__content">
			<p>ご注文から通常3〜5営業日でお届けします。お届け先の地域や在庫状況によって、お届けまでの日数が前後する場合がございます。</p>
			<p>お急ぎの場合は、翌日配送オプションもご利用いただけます(一部地域・商品を除く)。</p>
		</div>
	</details>

	<details class="accordion" name="demo">
		<summary class="accordion__title">
			<span>Q: 返品・交換は可能ですか?</span>
			<span class="accordion__icon" aria-hidden="true"></span>
		</summary>
		<div class="accordion__content">
			<p>商品到着後14日以内であれば、未開封・未使用に限り返品・交換を承ります。返品をご希望の場合は、カスタマーサポートまでご連絡ください。</p>
		</div>
	</details>

	<details class="accordion" name="demo">
		<summary class="accordion__title">
			<span>Q: 支払い方法は何が使えますか?</span>
			<span class="accordion__icon" aria-hidden="true"></span>
		</summary>
		<div class="accordion__content">
			<p>クレジットカード(VISA、Mastercard、JCB、American Express)、銀行振込、コンビニ決済、各種電子マネーがご利用いただけます。</p>
			<p>また、10,000円以上のご注文で分割払いもお選びいただけます。ご利用の際は決済画面で支払い回数をご指定ください。</p>
		</div>
	</details>
</div>
💡
ポイント
  • ::details-contentに対してgrid-template-rows0fr~1frへトランジションさせる.
  • transition-property: content-visibility & transition-behavior: allow-discreteの指定を忘れないように.
  • また、その子要素に対してoverflow: hiddenが必要なので、コンテンツはdiv(.accordion__content)でラップする.
  • ::details-contentを使うのは、まだあくまでアニメーション部分だけ(非サポートブラウザではただアニメーションがなくなるだけですむように。)
  • コンテンツにpaddingをつける時は.accordion__contentにつけて、open属性のない時はpadding-block0するようにする。もしくは、さらにdivでラップしてその中につける。

Can I use でcontent-visibility: Transitionable when setting transition-behavior: allow-discreteを確認するとFirefoxではサポートされていないことになっていますが、手元のFirefox v.145.0.2 では動作していました。

JS + CSSで開閉アニメーションを実装する例

Safariもサポートしつつアニメーションを実装するなら、JSの力を借りましょう。

スライドアニメーションは先ほどと同じ0fr~1frへのトランジションを使いますが、アニメーショントリガー用のdata-opened属性をJSでつけ外しするような実装をする例を紹介します。

ポイントは、open属性とタイミングをずらしてdata属性をつけ外しすることです。

<div class="accordions" data-multiple="disallow">
	<details class="accordion">
		<summary class="accordion__title">
			<span>Q: 配送にはどのくらいかかりますか?</span>
		</summary>
		<div class="accordion__body">
			<div class="accordion__content">
				<p>ご注文から通常3〜5営業日でお届けします。お届け先の地域や在庫状況によって、お届けまでの日数が前後する場合がございます。</p>
				<p>お急ぎの場合は、翌日配送オプションもご利用いただけます(一部地域・商品を除く)。</p>
			</div>
		</div>
	</details>

	<details class="accordion">
		<summary class="accordion__title">
			<span>Q: 返品・交換は可能ですか?</span>
		</summary>
		<div class="accordion__body">
			<div class="accordion__content">
				<p>
					商品到着後14日以内であれば、未開封・未使用に限り返品・交換を承ります。返品をご希望の場合は、カスタマーサポートまでご連絡ください。
				</p>
			</div>
		</div>
	</details>

	<details class="accordion">
		<summary class="accordion__title">
			<span>Q: 支払い方法は何が使えますか?</span>
		</summary>
		<div class="accordion__body">
			<div class="accordion__content">
				<p>クレジットカード(VISA、Mastercard、JCB、American Express)、銀行振込、コンビニ決済、各種電子マネーがご利用いただけます。</p>
				<p>また、10,000円以上のご注文で分割払いもお選びいただけます。ご利用の際は決済画面で支払い回数をご指定ください。</p>
			</div>
		</div>
	</details>
</div>

この実装の問題点

  • name属性を使って同一グループ内でのアコーディオン開閉を一つに制限すると、アニメーションがうまく動作しなくなります。

なので、それが気になる場合は独自実装が必要です。 上記の例では、data-multipleという属性を使って独自実装しています。

  • さらに、ページ内検索時の開閉アニメーションも完全には動作しません。

これらの開閉動作はtoggleイベントでopen属性の切り替え後にしか検知できないためです。

JSで開閉アニメーションを実装する例

最後に、一応アニメーションをフルでJSに任せた実装例を紹介します。

<div class="accordions" data-multiple="disallow">
	<details class="accordion">
		<summary class="accordion__title">
			<span>Q: 配送にはどのくらいかかりますか?</span>
		</summary>
		<div class="accordion__content">
			<p>ご注文から通常3〜5営業日でお届けします。お届け先の地域や在庫状況によって、お届けまでの日数が前後する場合がございます。</p>
			<p>お急ぎの場合は、翌日配送オプションもご利用いただけます(一部地域・商品を除く)。</p>
		</div>
	</details>
	<details class="accordion">
		<summary class="accordion__title">
			<span>Q: 返品・交換は可能ですか?</span>
		</summary>
		<div class="accordion__content">
			<p>商品到着後14日以内であれば、未開封・未使用に限り返品・交換を承ります。返品をご希望の場合は、カスタマーサポートまでご連絡ください。</p>
		</div>
	</details>
	<details class="accordion">
		<summary class="accordion__title">
			<span>Q: 支払い方法は何が使えますか?</span>
		</summary>
		<div class="accordion__content">
			<p>クレジットカード(VISA、Mastercard、JCB、American Express)、銀行振込、コンビニ決済、各種電子マネーがご利用いただけます。</p>
			<p>また、10,000円以上のご注文で分割払いもお選びいただけます。ご利用の際は決済画面で支払い回数をご指定ください。</p>
		</div>
	</details>
</div>

details/summary でのアニメーションに関しての基本的なことについては、ICSメディアさんの記事が非常に参考になりました。

それを元に、もう少しpaddingの融通が効くように調整を加えています。(コンテンツではなくdetailsheightをいじるようにした)

まとめ

本ページでは、detailssummary要素を使用したアコーディオンの実装方法を解説しました。

  • details/summary要素を使えば、JavaScriptなしでアクセシビリティの高いアコーディオンが実装できるだけでなく、開閉時のスライドアニメーションについても、CSSだけで実装できるようになっています。

参考リンク

CSSでheight: autoでもアニメーションが可能に! interpolate-sizeとは - ICS MEDIA UIのインタラクションの実装で、height: 0 → autoなど、数値とキーワード値とをアニメーションさせたいと思ったことはないでしょうか。一見可能そうに見えるものの、従来はCSSのみではアニメーションが不可能でした。
ICS MEDIA
detailsとsummaryタグで作るアコーディオンUI - アニメーションのより良い実装方法 - ICS MEDIA アコーディオン型ユーザーインターフェイス(UI)はウェブページでよくみられる表現です。巷ではさまざまな方法でアコーディオンUIを作る方法が紹介されていますが、みなさんはどのような方法で実装していますか。
ICS MEDIA
details要素に命を吹き込む::details-content擬似要素の登場 details要素のコンテンツ部分にスタイルを適用できる::details-content擬似要素がBaseline 2025に加わりました。details要素を用いたスタイリングの守備範囲が広がっただけではなく、アニメーションの適用も容易になりました。
k8o
CSSのみでdetails要素のアニメーションを実装する方法 &#8211; TAKLOG
www.tak-dcxi.com
アクセシブルなアコーディオンの実装について考える
Zenn