2026年5月20日

2026年5月20日

WordPressでタブ切り替えコンテンツを実装する方法

はじめに

タブ切り替えUIは、限られたスペースに複数のコンテンツを整理して表示できるUIパターンです。スペック比較・FAQ・カテゴリ別コンテンツの表示に適しています。

症状・原因

  • タブで切り替わるコンテンツを実装したい
  • ショートコードでタブをエディタから追加したい
  • URLのハッシュでタブを指定して開きたい
  • アクセシビリティに対応したタブにしたい

解決手順

ステップ1:タブのCSS

/* style.css */
.tab-wrapper {
    margin: 24px 0;
}

.tab-list {
    display: flex;
    gap: 0;
    border-bottom: 2px solid #c3c4c7;
    list-style: none;
    padding: 0;
    margin: 0;
    overflow-x: auto;
}

.tab-button {
    padding: 10px 20px;
    border: none;
    border-bottom: 2px solid transparent;
    background: none;
    cursor: pointer;
    font-size: 14px;
    color: #50575e;
    white-space: nowrap;
    margin-bottom: -2px;
    transition: color 0.2s, border-color 0.2s;
}

.tab-button[aria-selected="true"] {
    color: #2271b1;
    border-bottom-color: #2271b1;
    font-weight: 600;
}

.tab-button:hover {
    color: #2271b1;
}

.tab-panel {
    padding: 20px 0;
    display: none;
}

.tab-panel.is-active {
    display: block;
}

ステップ2:JavaScriptでタブ切り替え

// js/tab.js
document.addEventListener('DOMContentLoaded', function() {

    document.querySelectorAll('.tab-wrapper').forEach(function(wrapper) {
        const buttons = wrapper.querySelectorAll('.tab-button');
        const panels  = wrapper.querySelectorAll('.tab-panel');

        function activateTab(index) {
            buttons.forEach(function(btn, i) {
                const isActive = i === index;
                btn.setAttribute('aria-selected', isActive ? 'true' : 'false');
                btn.setAttribute('tabindex', isActive ? '0' : '-1');
            });
            panels.forEach(function(panel, i) {
                panel.classList.toggle('is-active', i === index);
                panel.setAttribute('hidden', i === index ? null : 'hidden');
            });
        }

        buttons.forEach(function(btn, index) {
            btn.addEventListener('click', function() {
                activateTab(index);
                // URLハッシュを更新
                const hash = btn.getAttribute('data-tab-hash');
                if (hash) history.replaceState(null, '', '#' + hash);
            });

            // キーボード操作(左右矢印キー)
            btn.addEventListener('keydown', function(e) {
                if (e.key === 'ArrowRight') {
                    activateTab((index + 1) % buttons.length);
                    buttons[(index + 1) % buttons.length].focus();
                }
                if (e.key === 'ArrowLeft') {
                    activateTab((index - 1 + buttons.length) % buttons.length);
                    buttons[(index - 1 + buttons.length) % buttons.length].focus();
                }
            });
        });

        // URLハッシュで初期タブを指定
        const hash = location.hash.replace('#', '');
        if (hash) {
            const target = wrapper.querySelector(`[data-tab-hash="${hash}"]`);
            if (target) {
                const idx = Array.from(buttons).indexOf(target);
                if (idx >= 0) activateTab(idx);
            }
        }
    });
});

ステップ3:ショートコードで実装

// functions.php
add_shortcode('tabs', function(array $atts, ?string $content = null): string {
    $id = 'tabs-' . wp_rand(1000, 9999);
    return '<div class="tab-wrapper" id="' . esc_attr($id) . '">'
        . do_shortcode($content ?? '')
        . '</div>';
});

add_shortcode('tab', function(array $atts, ?string $content = null): string {
    $atts = shortcode_atts(['title' => 'タブ', 'hash' => ''], $atts, 'tab');
    static $index = 0;

    $title = esc_html($atts['title']);
    $hash  = sanitize_title($atts['hash'] ?: $atts['title']);
    $btn_id = 'tab-btn-' . (++$index);
    $pnl_id = 'tab-pnl-' . $index;

    return '<button class="tab-button" role="tab" id="' . $btn_id . '"
        aria-controls="' . $pnl_id . '" aria-selected="false"
        tabindex="-1" data-tab-hash="' . esc_attr($hash) . '">'
        . $title . '</button>'
        . '<div class="tab-panel" role="tabpanel" id="' . $pnl_id . '"
        aria-labelledby="' . $btn_id . '" hidden>'
        . wp_kses_post(do_shortcode($content ?? ''))
        . '</div>';
});

使用例(投稿エディタで):

[tabs]
[tab title="概要" hash="overview"]概要の内容[/tab]
[tab title="機能" hash="features"]機能の内容[/tab]
[tab title="料金" hash="price"]料金の内容[/tab]
[/tabs]

ステップ4:スクリプトのエンキュー

// functions.php
add_action('wp_enqueue_scripts', function(): void {
    wp_enqueue_script(
        'tab-content',
        get_template_directory_uri() . '/js/tab.js',
        [],
        filemtime(get_template_directory() . '/js/tab.js'),
        true
    );
});

注意事項

  • role="tablist"role="tab"role="tabpanel" のARIA属性を正確に設定してください。スクリーンリーダーがタブUIとして認識します
  • タブボタンにはキーボード操作(左右矢印キー)を実装してください。WAI-ARIAのタブパターンの要件です
  • ショートコードの static $index はリクエスト内でのみ有効です。同じページに複数のタブがある場合でも一意のIDを保証します

まとめ

タブUIは role="tab" + aria-selected + 矢印キー対応で実装します。CSSは .tab-button[aria-selected="true"] でアクティブスタイルを定義し、パネルは .is-active クラスで表示切り替えします。URLハッシュ連動で直リンクから特定タブを開くことができます。

お気軽にご相談ください

お見積りへ お問い合わせへ