details と summary で開閉できる内容を作る
内容を <details> で囲み、最初に <summary> を置きます。summary は表示されたままで、ほかの内容は読者がクリックするまで隠れています。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>details</title>
</head>
<body style="font-family: system-ui, sans-serif;">
<details>
<summary>What is included in the free plan?</summary>
<p>Five projects, community support and all the beginner courses.</p>
</details>
</body>
</html>Master HTML the hands-on way
Interactive lessons, real projects, and instant feedback.
START NOW
質問をクリックすると開き、もう一度クリックすると閉じます。ブラウザが三角の印を付け、summary をフォーカスできるようにし、Enter キーやスペースキーで開閉させ、展開されているか折りたたまれているかをスクリーンリーダーに伝えます。JavaScript はまったく使っていません。
<summary> を省くと、代わりにブラウザが初期のラベル (英語では「Details」) を表示します。
最初から開いておく
真偽値の open 属性を付けると、最初から内容が表示されます。読者が開閉するとブラウザが open を追加したり外したりするので、スタイルを付ける手がかりにもなります。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>open</title>
<style>
body { font-family: system-ui, sans-serif; margin: 12px; }
details { border: 2px solid #e5e7eb; border-radius: 8px; padding: 8px 12px; margin-bottom: 8px; }
details[open] { border-color: #2563eb; }
summary { cursor: pointer; font-weight: 600; }
</style>
</head>
<body>
<details open>
<summary>Shipping</summary>
<p>Orders ship within two working days.</p>
</details>
<details>
<summary>Returns</summary>
<p>Return any item within 30 days.</p>
</details>
</body>
</html>
開いている箱には details[open] で青い枠線が付いています。「Returns」を開くとそれも青くなります。両方を同時に開いておけます。
アコーディオン: 一度に 1 つだけ開く
複数の <details> 要素に同じ name を付けると、排他的なグループになります。1 つを開くとほかのものが閉じます。以前は JavaScript が必要でしたが、現在の Chrome、Edge、Firefox、Safari では属性だけで動きます。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Accordion</title>
<style>
body { font-family: system-ui, sans-serif; margin: 12px; }
.faq { max-width: 420px; border: 1px solid #e5e7eb; border-radius: 10px; }
.faq details + details { border-top: 1px solid #e5e7eb; }
.faq summary { padding: 12px 14px; cursor: pointer; font-weight: 600; }
.faq p { margin: 0; padding: 0 14px 12px; color: #374151; }
</style>
</head>
<body>
<div class="faq">
<details name="faq" open>
<summary>Is it free?</summary>
<p>Yes, the basics are free forever.</p>
</details>
<details name="faq">
<summary>Do I need to install anything?</summary>
<p>No, everything runs in the browser.</p>
</details>
<details name="faq">
<summary>Can I cancel any time?</summary>
<p>Yes, from your account settings.</p>
</details>
</div>
</body>
</html>
2 つ目の質問を開くと 1 つ目が閉じます。name 属性を消すと、それぞれが独立して開くようになります。排他的なアコーディオンは読者が比べたいかもしれない内容を隠してしまうので、セクションが選択肢同士であるときに使い、複数を開きたい場合がありそうなら普通の <details> を使いましょう。
印のデザイン
三角は summary に付いたリストの印 (マーカー) です。list-style: none で消し (::-webkit-details-marker のルールは Safari 向けです)、疑似要素で独自の印を描けます。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Custom marker</title>
<style>
body { font-family: system-ui, sans-serif; margin: 12px; }
details { max-width: 420px; background: #f9fafb; border-radius: 8px; margin-bottom: 8px; }
summary {
list-style: none; cursor: pointer;
display: flex; justify-content: space-between; align-items: center;
padding: 12px 14px; font-weight: 600;
}
summary::-webkit-details-marker { display: none; }
summary::after {
content: "+"; font-size: 20px; color: #2563eb;
transition: transform 0.2s;
}
details[open] summary::after { transform: rotate(45deg); }
summary:focus-visible { outline: 3px solid #2563eb; outline-offset: 2px; border-radius: 8px; }
details p { margin: 0; padding: 0 14px 12px; }
</style>
</head>
<body>
<details>
<summary>How long are the lessons?</summary>
<p>Most lessons take five to ten minutes.</p>
</details>
<details>
<summary>Do I get a certificate?</summary>
<p>Yes, when you finish a course.</p>
</details>
</body>
</html>
セクションが開くと、プラス記号が 45 度回転してバツ印になります。ここにある :focus-visible の outline のように、フォーカスのスタイルは見えるように残しましょう。初期の印を消したら、キーボードのユーザーが頼りにするのはフォーカスリングです。
toggle イベントと open プロパティ
JavaScript では details.open を読み書きでき、クリック、キー操作、スクリプトのどれで変わった場合でも、変化のたびに toggle イベントが発生します。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>toggle</title>
<style>
body { font-family: system-ui, sans-serif; margin: 12px; }
button { font: inherit; padding: 4px 10px; margin-inline-end: 6px; }
details { margin-top: 10px; border: 2px solid #e5e7eb; border-radius: 8px; padding: 8px 12px; }
#log { color: #16a34a; }
</style>
</head>
<body>
<button id="expand">Expand all</button>
<button id="collapse">Collapse all</button>
<details><summary>Step 1</summary><p>Create an account.</p></details>
<details><summary>Step 2</summary><p>Pick a course.</p></details>
<p id="log">Nothing toggled yet.</p>
<script>
const all = document.querySelectorAll('details');
all.forEach((d) => d.addEventListener('toggle', () => {
document.getElementById('log').textContent =
d.querySelector('summary').textContent + (d.open ? ' opened' : ' closed');
}));
document.getElementById('expand').onclick = () => all.forEach((d) => { d.open = true; });
document.getElementById('collapse').onclick = () => all.forEach((d) => { d.open = false; });
</script>
</body>
</html>
「Expand all」は両方に open を設定し、ログには最後の toggle イベントが表示されます。このイベントはバブリングしないので、親ではなく各 <details> 要素で受け取りましょう。
summary に入れるもの
summary にはテキスト、インライン要素、またはセクションのタイトルをページのアウトラインに含めたいときは見出しを入れます。
<details>
<summary><h3>Refund policy</h3></summary>
<p>...</p>
</details>
<summary> の中にリンク、ボタン、フォームの入力欄を置くのは避けましょう。summary 自体がすでに操作できる部品なので、その中の部品は見落としやすく、間違って押しやすく、スクリーンリーダーも入れ子の部品をうまく読み上げられません。操作できる内容は <details> の本体に置きましょう。
よくある間違い
<div> と JavaScript で開閉を作る。 <details> はクリック、キー操作、スクリーンリーダーへの状態の通知をすでに処理しています。独自の開閉がどうしても必要なら、aria-expanded を付けた ボタン を使いましょう。
<summary> を最初以外の場所に置く。 <details> の最初の子要素でなければなりません。
代わりを用意せずに印を消す。 上のプラス記号のように、summary を開けることが読者にわかる印を付けましょう。
display で内容を隠す。 代わりに open を切り替えましょう。内容を強制的に表示したり隠したりする CSS は、ブラウザの状態とぶつかります。
比べたい内容に排他的なグループを使う。 name は、一度に 1 つだけ開くことに意味があるときだけ使いましょう。