【jQuery】アコーディオンの実装完全ガイド|FAQ・単体開閉・複数展開・アイコン回転まで

アコーディオンはFAQや設定パネルなどに広く使われるUIパターンです。jQueryの slideToggle() を使えば簡単に実装できますが、単体のみ展開・複数同時展開・アイコン回転・アクセシビリティ対応まできちんと作り込むと完成度が格段に上がります。

この記事でわかること

  • slideToggle()を使った基本的なアコーディオン
  • 1つだけ開く(他を閉じる)排他制御の実装
  • 複数同時展開を許可するアコーディオン
  • 開閉アイコン(▼/▲)の回転アニメーション
  • URLハッシュで特定の項目を初期展開する方法
  • アクセシビリティ(aria属性)の対応
スポンサーリンク

1. 基本:slideToggle()を使ったアコーディオン

最もシンプルな実装です。ヘッダーをクリックすると対応するコンテンツがスライドで開閉します。

<div class="accordion">
  <div class="ac-header">質問1:jQueryとは何ですか?</div>
  <div class="ac-body">jQueryはJavaScriptのライブラリです。</div>
</div>
<div class="accordion">
  <div class="ac-header">質問2:無料で使えますか?</div>
  <div class="ac-body">はい、MITライセンスで無料です。</div>
</div>
.ac-body { display: none; }  /* 初期非表示 */
.ac-header { cursor: pointer; padding: 12px 16px; background: #f1f5f9; border: 1px solid #e2e8f0; }
.ac-body   { padding: 12px 16px; border: 1px solid #e2e8f0; border-top: none; }
$(function () {
  $('.ac-header').on('click', function () {
    $(this).next('.ac-body').slideToggle(250);
  });
});

2. 排他制御:1つだけ展開する(他を自動で閉じる)

クリックした項目を開くと同時に、他の開いている項目を閉じるパターンです。FAQに多く使われます。

$(function () {
  $('.ac-header').on('click', function () {
    var $body   = $(this).next('.ac-body');
    var isOpen  = $body.is(':visible');

    // 全てのコンテンツを閉じる
    $('.ac-body').slideUp(200);
    $('.ac-header').removeClass('is-open');

    // クリックした項目が閉じていた場合のみ開く
    if (!isOpen) {
      $body.slideDown(200);
      $(this).addClass('is-open');
    }
  });
});

3. 開閉アイコン(▼)の回転アニメーション

ヘッダーに矢印アイコンを付けて、開いているときは上向き・閉じているときは下向きに回転させます。

<div class="accordion2">
  <div class="ac2-header">
    <span class="ac2-title">質問1:料金はいくらですか?</span>
    <span class="ac2-icon">▼</span>
  </div>
  <div class="ac2-body">月額980円です。</div>
</div>
.ac2-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  cursor: pointer;
  padding: 14px 16px;
  background: #f8fafc;
  border: 1px solid #e2e8f0;
}
.ac2-icon {
  transition: transform 0.25s ease;
  display: inline-block;
}
.ac2-header.is-open .ac2-icon {
  transform: rotate(180deg);  /* 開いているとき上向き */
}
.ac2-body { display: none; padding: 14px 16px; border: 1px solid #e2e8f0; border-top: none; }
$(function () {
  $('.ac2-header').on('click', function () {
    var $body = $(this).next('.ac2-body');

    // 全て閉じてから対象を開く(排他制御)
    $('.ac2-body').not($body).slideUp(200);
    $('.ac2-header').not(this).removeClass('is-open');

    $body.slideToggle(200);
    $(this).toggleClass('is-open');
  });
});
CSSトランジションでアイコンを回転
.ac2-icontransition: transform 0.25s ease を設定し、.is-open クラスのときに rotate(180deg) を適用します。jQueryでクラスの付け替えだけすれば、アニメーションはCSSが担当します。

4. URLハッシュで特定の項目を初期展開

example.com/faq/#q3 のようにURLにハッシュを含む場合、対応する項目を初期状態で開くUXが親切です。

<div class="accordion" id="q1">
  <div class="ac-header">質問1</div>
  <div class="ac-body">回答1</div>
</div>
<div class="accordion" id="q2">
  <div class="ac-header">質問2</div>
  <div class="ac-body">回答2</div>
</div>
<div class="accordion" id="q3">
  <div class="ac-header">質問3</div>
  <div class="ac-body">回答3</div>
</div>
$(function () {
  var hash = location.hash;  // "#q3" のような文字列

  if (hash) {
    var $target = $(hash);
    if ($target.length) {
      $target.find('.ac-body').show();
      $target.find('.ac-header').addClass('is-open');
      // 対象位置までスクロール
      $(['html', 'body'].join(',')).animate({ scrollTop: $target.offset().top - 80 }, 400);
    }
  }
});

5. アクセシビリティ対応(aria属性)

スクリーンリーダーに対応するには aria-expandedaria-controls を適切に設定します。

<button class="ac-header"
        aria-expanded="false"
        aria-controls="panel1">
  質問1
</button>
<div class="ac-body" id="panel1" role="region">
  回答1
</div>
$(function () {
  $('.ac-header').on('click', function () {
    var $btn   = $(this);
    var $panel = $('#' + $btn.attr('aria-controls'));
    var isOpen = $btn.attr('aria-expanded') === 'true';

    // 全て閉じる
    $('.ac-header').attr('aria-expanded', 'false');
    $('.ac-body').slideUp(200);

    // 対象を切り替え
    if (!isOpen) {
      $btn.attr('aria-expanded', 'true');
      $panel.slideDown(200);
    }
  });
});
button要素を使うとキーボード操作が自動で有効になる
ヘッダーに <div> ではなく <button> を使うと、Enterキーおよびスペースキーでの操作がブラウザのデフォルト動作として有効になります。アクセシビリティの観点から推奨です。

まとめ

jQueryのアコーディオン実装はシンプルな slideToggle() から始められますが、排他制御・アイコン回転・URLハッシュ対応・aria属性まで組み合わせると実用的なUIになります。

機能 実装のポイント
基本開閉 slideToggle(250)
排他制御 slideUp()で全閉→対象だけslideDown()
アイコン回転 CSSのrotate()+is-openクラスの付け替え
URLハッシュ初期展開 location.hashで対象IDを検索して.show()
アクセシビリティ button要素+aria-expanded属性

関連記事: jQueryのアニメーション完全ガイド(slideDown/slideUp/fadeIn) / jQueryのclass追加と削除でアニメーションを制御する方法

よくある質問(FAQ)

Qアコーディオンで他の項目を自動で閉じるには?
Aクリック時にまず全ての .ac-bodyslideUp() で閉じ、その後クリックされた項目だけを slideDown() で開きます。直前の状態(開いているか)を確認して同じ項目をクリックしたら閉じるようにするとUXが向上します(セクション2参照)。
Qアコーディオンのアイコンを回転させるには?
Aアイコン要素に transition: transform 0.25s をCSSで設定し、開いているときは .is-open .ac-icon { transform: rotate(180deg); } を適用します。jQueryでは toggleClass('is-open') でクラスを切り替えるだけでOKです。
Q複数のアコーディオンを同時に開けるようにするには?
A排他制御(全閉→1つ開く)をやめて、単純に slideToggle() だけにすれば複数同時展開になります。$('.ac-body').slideUp() の行を削除するだけで切り替わります。
Q特定の項目をデフォルトで開いた状態にするには?
A対象の .ac-body にCSSで display: block を直接設定するか、初期化時に $('.ac-body').eq(0).show() で最初の項目を表示します。あわせてヘッダーに .is-open クラスも付けておきましょう。
Qスクリーンリーダーに対応するには?
Aヘッダーを <button> 要素にして aria-expanded 属性を開閉に合わせて "true"/"false" に切り替えます。コンテンツには idrole="region" を付けて aria-controls で関連付けます。