jQueryでボタンを押すたびに文章を表示・非表示へ切り替えるには、toggle()を使います。FAQの回答や補足パネルを、短いコードで開閉できます。
ただし、表示を切り替えるだけでは、キーボードや読み上げソフトを使う人に開閉状態が伝わりません。実際の制作ではbutton要素を使い、aria-expandedも一緒に更新します。
この記事では、toggle()の基本、速度の指定、slideToggle()との違い、アクセシブルなFAQ、連打時や動かないときの対処まで、実際の表示画像とコードで解説します。
jQueryのtoggle()とは
toggle()は、選択した要素が表示中なら非表示にし、非表示なら表示するjQueryのメソッドです。英語のtoggleには、2つの状態を交互に切り替えるという意味があります。

基本形は次のとおりです。#detailsは表示を切り替えたい要素のIDです。
$('#details').toggle();toggle()を実行するきっかけには、クリックイベントを使うことが多いです。ボタンが押されたときに対象を切り替える基本コードは次のようになります。
$('#toggle-button').on('click', function () {
$('#details').toggle();
});toggle()・slideToggle()・fadeToggle()・toggleClass()の違い
jQueryには名前が似た切り替え用メソッドがあります。作りたい動きに合わせて選びましょう。
| メソッド | 切り替わり方 | 向いている用途 |
|---|---|---|
toggle() | 表示・非表示を切り替える。時間を指定すると幅・高さ・透明度などが変化する | 補足パネル、単純な開閉 |
slideToggle() | 高さを動かし、上下へ開閉する | FAQ、アコーディオン |
fadeToggle() | 透明度を変えながら表示・非表示を切り替える | 画像、案内メッセージ |
toggleClass() | 指定したclassを追加・削除する | 色、アイコン、選択状態などの見た目 |
単純に瞬時に切り替えるならtoggle()、FAQのように下へ開く動きならslideToggle()が分かりやすいです。見た目だけを変える場合はtoggleClass()を使い、CSSへデザインをまとめます。
補足パネルをtoggle()で開閉する実例
「詳しい内容を見る」ボタンを押すと、コース内容が表示される例を作ります。最初は次のように補足パネルを隠しておきます。

HTMLでボタンとパネルを関連付ける
HTMLはindex.htmlへ記述します。操作部分にはdivではなく、EnterキーとSpaceキーでも押せるbutton要素を使います。
<!doctype html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>jQuery toggleの基本例</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<main class="demo">
<p class="demo__label">jQuery .toggle()</p>
<h1>コースの詳しい内容を切り替えます</h1>
<p class="lead">
ボタンを押すたびに、補足パネルの表示と非表示が入れ替わります。
</p>
<button
id="details-button"
class="toggle-button"
type="button"
aria-expanded="false"
aria-controls="details-panel"
>
詳しい内容を見る
<span aria-hidden="true">+</span>
</button>
<section id="details-panel" class="details-panel">
<p class="details-panel__label">Web制作 入門コース</p>
<h2>手を動かしながら3つの基本を学びます</h2>
<ul>
<li>HTMLでページの構造を作る</li>
<li>CSSで見た目とレイアウトを整える</li>
<li>jQueryでクリック操作を追加する</li>
</ul>
</section>
</main>
<script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
<script src="script.js"></script>
</body>
</html>aria-controls="details-panel"は、このボタンがどの要素を操作するかを示します。aria-expanded="false"は、現在閉じている状態を支援技術へ伝えます。
CSSで初期状態を非表示にする
style.cssでは、補足パネルへdisplay: noneを指定します。これが読み込み直後の閉じた状態です。
:root {
color: #172033;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
background: #edf3fb;
}
* {
box-sizing: border-box;
}
body {
min-height: 100vh;
margin: 0;
padding: 42px 24px;
display: grid;
place-items: center;
}
.demo {
width: min(940px, 100%);
min-height: 620px;
padding: 54px;
border: 1px solid #dae4f2;
border-radius: 28px;
background: #fff;
box-shadow: 0 26px 72px rgb(42 63 104 / 13%);
}
.demo__label {
margin: 0 0 12px;
color: #2966d2;
font-weight: 800;
letter-spacing: .08em;
}
h1 {
margin: 0;
font-size: clamp(34px, 5vw, 48px);
line-height: 1.3;
}
.lead {
margin: 16px 0 28px;
color: #5a667c;
font-size: 18px;
line-height: 1.8;
}
.toggle-button {
width: 100%;
min-height: 62px;
padding: 16px 20px;
display: flex;
justify-content: space-between;
align-items: center;
border: 0;
border-radius: 14px;
color: #fff;
background: #2966d2;
font: inherit;
font-weight: 800;
cursor: pointer;
}
.toggle-button:focus-visible {
outline: 4px solid #f5bd42;
outline-offset: 4px;
}
.toggle-button span {
font-size: 26px;
line-height: 1;
}
.details-panel {
display: none;
margin-top: 16px;
padding: 28px;
border: 1px solid #cbd8ec;
border-radius: 18px;
background: #f8faff;
}
.details-panel__label {
margin: 0;
color: #2966d2;
font-weight: 800;
}
.details-panel h2 {
margin: 8px 0 14px;
font-size: 25px;
}
.details-panel ul {
margin: 0;
padding-left: 1.4em;
color: #4f5c73;
line-height: 1.9;
}
@media (max-width: 640px) {
body {
padding: 20px;
}
.demo {
min-height: 0;
padding: 32px 24px;
}
}display: noneがないと、最初からパネルが表示され、aria-expanded="false"と実際の状態が食い違います。HTML・CSS・ARIAの初期状態をそろえてください。
クリック時に表示とARIAを切り替える
script.jsでは、現在のaria-expandedを確認して、これから開くかどうかをwillOpenへ保存します。
const $detailsButton = $('#details-button');
const $detailsPanel = $('#details-panel');
$detailsButton.on('click', function () {
const willOpen = $detailsButton.attr('aria-expanded') === 'false';
$detailsPanel.toggle();
$detailsButton.attr('aria-expanded', String(willOpen));
$detailsButton.find('span').text(willOpen ? '−' : '+');
});toggle()がパネルを切り替え、attr()が開閉状態を更新します。三項演算子条件 ? 開いた値 : 閉じた値で、アイコンもプラスとマイナスへ切り替えています。

もう一度押すとパネルは消え、アイコンはプラス、aria-expandedはfalseへ戻ります。掲載画像は、このコードをブラウザで実行した結果です。
toggle()の速度を指定する
toggle()へミリ秒を渡すと、指定時間をかけて表示・非表示を切り替えます。1000ミリ秒は1秒です。
$('#toggle-button').on('click', function () {
$('#details').toggle(300);
});| 指定 | 切り替え時間 |
|---|---|
toggle() | アニメーションなし |
toggle(300) | 300ミリ秒 |
toggle('fast') | 200ミリ秒 |
toggle('slow') | 600ミリ秒 |
時間が大きいほどゆっくり動きます。1秒以上の長い動きは操作を待たせているように感じやすいため、通常は200〜400ミリ秒程度から調整すると自然です。
連打でアニメーションが続く場合はstop()を使う
アニメーション中に何度も押すと、jQueryの処理待ちに動きがたまり、クリックをやめたあとも開閉が続くことがあります。stop(true, true)で、それまでの待ちを終えてから切り替えます。
$('#toggle-button').on('click', function () {
$('#details').stop(true, true).toggle(300);
});最初のtrueは待機中のアニメーションを削除し、2つ目のtrueは現在のアニメーションを終了状態まで進めます。
slideToggle()でFAQアコーディオンを作る
FAQは、回答が上下へ開くslideToggle()と相性のよいUIです。質問を見出しの中のボタンにし、回答のIDとaria-controlsを対応させます。

FAQのHTMLを書く
同じ構造を質問の数だけ繰り返します。IDはページ内で重複しない名前にしてください。
<div class="faq-list">
<section class="faq-item">
<h2>
<button
class="faq-button"
type="button"
aria-expanded="false"
aria-controls="faq-panel-1"
>
初心者でも受講できますか?
<span aria-hidden="true">+</span>
</button>
</h2>
<div id="faq-panel-1" class="faq-panel">
<p>
はい。HTMLを書いたことがない方も、ファイルの作り方から順番に学べます。
</p>
</div>
</section>
<section class="faq-item">
<h2>
<button
class="faq-button"
type="button"
aria-expanded="false"
aria-controls="faq-panel-2"
>
スマートフォンでも学べますか?
<span aria-hidden="true">+</span>
</button>
</h2>
<div id="faq-panel-2" class="faq-panel">
<p>
閲覧はできますが、コードを書く練習にはパソコンの利用がおすすめです。
</p>
</div>
</section>
</div>ボタンは見出しの唯一の子要素にしています。ネイティブのbuttonを使うため、追加のキーボードイベントを書かなくてもEnterキーとSpaceキーで操作できます。
FAQのCSSを書く
.faq-list {
display: grid;
gap: 14px;
}
.faq-item {
overflow: hidden;
border: 1px solid #ccd8ea;
border-radius: 16px;
background: #fff;
}
.faq-item h2 {
margin: 0;
}
.faq-button {
width: 100%;
min-height: 68px;
padding: 18px 22px;
display: flex;
justify-content: space-between;
align-items: center;
gap: 18px;
border: 0;
color: #172033;
background: #f8faff;
font: inherit;
font-size: 19px;
font-weight: 800;
text-align: left;
cursor: pointer;
}
.faq-button[aria-expanded="true"] {
color: #1f57b8;
background: #edf4ff;
}
.faq-button:focus-visible {
outline: 4px solid #f5bd42;
outline-offset: -4px;
}
.faq-panel {
display: none;
padding: 0 22px 22px;
background: #edf4ff;
}
.faq-panel p {
margin: 0;
padding-top: 16px;
border-top: 1px solid #cbd9ef;
color: #4f5c73;
line-height: 1.8;
}[aria-expanded="true"]は、開いているボタンだけへ適用される属性セレクタです。JavaScriptが更新した状態を利用して色も変えられます。
選んだ質問の次にある回答を開く
クリックされたボタンのaria-controlsから、対応する回答のIDを取得します。これなら質問が複数あっても、選んだ回答だけを開閉できます。
const $faqButtons = $('.faq-button');
$faqButtons.on('click', function () {
const $button = $(this);
const willOpen = $button.attr('aria-expanded') === 'false';
const panelId = $button.attr('aria-controls');
const $panel = $(`#${panelId}`);
$panel.stop(true, true).slideToggle(250);
$button.attr('aria-expanded', String(willOpen));
$button.find('span').text(willOpen ? '−' : '+');
});thisは押されたボタンを指します。slideToggle(250)は250ミリ秒で開閉し、stop(true, true)は連打によるアニメーションの滞留を防ぎます。
ブラウザで、クリックだけでなくTabキーで質問へ移動し、EnterキーとSpaceキーでも回答が開閉するか確認してください。ボタンの状態と回答の表示が一致することも重要です。
動きを減らす設定へ対応する
端末で「視差効果を減らす」などを設定している人には、アニメーションを使わず瞬時に切り替えます。JavaScriptからprefers-reduced-motionを確認しましょう。
const reduceMotion = window.matchMedia(
'(prefers-reduced-motion: reduce)'
).matches;
const duration = reduceMotion ? 0 : 250;
$panel.stop(true, true).slideToggle(duration);toggleClass()で見た目の状態を切り替える
toggle()は要素そのものの表示・非表示を変えます。色やアイコンなどの見た目を切り替えたい場合は、toggleClass()でclassを追加・削除し、CSSへデザインを記述します。
$('#favorite-button').on('click', function () {
const $button = $(this);
const willSelect = $button.attr('aria-pressed') === 'false';
$button.toggleClass('is-selected', willSelect);
$button.attr('aria-pressed', String(willSelect));
});toggleClass('is-selected', true)なら追加、falseなら削除します。トグルボタンのラベルは「お気に入り」のように変えず、押された状態をaria-pressedで伝えます。
あとから追加した要素をtoggleする
Ajaxなどであとから追加されるボタンには、ページ読み込み時の$('.faq-button').on(...)ではイベントが付きません。最初から存在する親要素へイベントを設定します。
$('.faq-list').on('click', '.faq-button', function () {
const $button = $(this);
const panelId = $button.attr('aria-controls');
$(`#${panelId}`).stop(true, true).slideToggle(250);
});この書き方をイベントの委譲と呼びます。実際のFAQでは、前の例と同じようにaria-expandedとアイコンの更新も追加してください。
toggle()が動かないときの確認項目
jQueryを先に読み込んでいるか
開発者ツールに$ is not definedと表示されたら、jQuery本体が読み込めていません。jQueryのscriptタグを、自分のscript.jsより前へ置きます。
セレクタが対象と一致しているか
$('#details')はid="details"を探し、$('.details')はclass="details"を探します。シャープとピリオド、スペル、大文字・小文字を確認してください。
同じclassの要素がすべて切り替わっていないか
$('.answer').toggle()は、一致する回答をすべて切り替えます。クリックした質問に対応する1つだけを変えるなら、this、next()、またはaria-controlsから対象を特定しましょう。
CSSの!importantが邪魔をしていないか
display: block !importantなどがあると、jQueryがインラインで指定したdisplay: noneより優先され、隠れない場合があります。開発者ツールのStylesで、取り消し線になっているdisplayを確認してください。
初期表示とaria-expandedが食い違っていないか
回答が見えているのにaria-expanded="false"になっていると、支援技術へ誤った状態を伝えます。閉じて開始するならCSSをdisplay: none、ARIAをfalseにそろえます。
古いtoggleイベントとの違い
古い記事では、複数の関数を渡してクリックごとに交互実行するtoggle(handler, handler)を見かけることがあります。このイベント用シグネチャは非推奨になったあと、jQuery 1.9で削除されました。
// 古い書き方:使用しません
$('#button').toggle(
function () {
console.log('1回目');
},
function () {
console.log('2回目');
}
);
// 現在はclickイベント内で状態を切り替えます
$('#button').on('click', function () {
$('#details').toggle();
});表示・非表示を切り替えるtoggle()は別のメソッドとして利用できます。「toggleは削除された」という説明を見たら、イベント用の古い書き方かどうかを確認してください。
よくある質問
最初から表示しておき、最初のクリックで隠せますか?
できます。対象からdisplay: noneを外し、操作ボタンのaria-expandedをtrueにします。初期状態をHTML・CSS・ARIAの3か所で一致させてください。
FAQは1つだけ開く形にできますか?
できます。クリックされた回答を開く前に、ほかの回答をslideUp()で閉じ、ほかのボタンのaria-expandedをfalseへ戻します。
$('.faq-button').on('click', function () {
const $button = $(this);
const willOpen = $button.attr('aria-expanded') === 'false';
const $panel = $(`#${$button.attr('aria-controls')}`);
$('.faq-panel').not($panel).stop(true, true).slideUp(250);
$('.faq-button').not($button).attr('aria-expanded', 'false');
$panel.stop(true, true).slideToggle(250);
$button.attr('aria-expanded', String(willOpen));
});toggle()だけでハンバーガーメニューを作れますか?
表示の切り替えはできますが、メニューボタンのaria-expanded、メニュー外を押したときやEscキーで閉じる処理、フォーカスの扱いも必要です。単にnav.toggle()だけで完成とは考えないようにしましょう。
まとめ
toggle()は表示中の要素を隠し、非表示の要素を表示する- FAQの上下開閉には
slideToggle()が使いやすい - 色や選択状態は
toggleClass()でCSSのclassを切り替える - 操作にはネイティブの
buttonを使い、aria-expandedも更新する - アニメーションの連打対策には
stop(true, true)を使う - 古い
toggle(handler, handler)は削除済みだが、表示用のtoggle()は利用できる
まずは補足パネルの例をそのまま動かし、マウス、Tabキー、Enterキー、Spaceキーで開閉してみてください。画面の表示、プラス・マイナス、aria-expandedの3つが同じ状態になれば、基本の切り替えは完成です。
