Accessible Tabs Shortcode
Adds [wpide_tabs] and [wpide_tab title="..."] shortcodes to build tabbed content that works with mouse, keyboard (arrow keys) and screen readers.
Opens WPIDE on
Code
add_action( 'wp_enqueue_scripts', function () {
wp_register_style( 'wpide-tabs', false, array(), '1.0' );
wp_add_inline_style( 'wpide-tabs', '.wpide-tabs__list{display:flex;flex-wrap:wrap;gap:4px;border-bottom:1px solid rgba(0,0,0,.15);margin-bottom:1em;}.wpide-tabs__tab{appearance:none;border:0;background:none;padding:.6em 1em;font:inherit;cursor:pointer;color:inherit;border-bottom:3px solid transparent;margin-bottom:-1px;}.wpide-tabs__tab[aria-selected="true"]{border-bottom-color:currentColor;font-weight:600;}.wpide-tabs__tab:focus-visible{outline:2px solid currentColor;outline-offset:2px;}.wpide-tabs__panel[hidden]{display:none;}' );
wp_register_script( 'wpide-tabs', false, array(), '1.0', true );
wp_add_inline_script( 'wpide-tabs', <<<'JS'
document.querySelectorAll('.wpide-tabs').forEach(function (wrap) {
var panels = Array.prototype.slice.call(wrap.querySelectorAll(':scope > .wpide-tabs__panel'));
if (!panels.length) { return; }
var list = document.createElement('div');
list.className = 'wpide-tabs__list';
list.setAttribute('role', 'tablist');
var tabs = panels.map(function (panel, i) {
var tab = document.createElement('button');
tab.type = 'button';
tab.className = 'wpide-tabs__tab';
tab.id = panel.id + '-tab';
tab.textContent = panel.getAttribute('data-title') || ('Tab ' + (i + 1));
tab.setAttribute('role', 'tab');
tab.setAttribute('aria-controls', panel.id);
panel.setAttribute('role', 'tabpanel');
panel.setAttribute('aria-labelledby', tab.id);
panel.setAttribute('tabindex', '0');
list.appendChild(tab);
return tab;
});
function select(index, focus) {
tabs.forEach(function (tab, i) {
var on = i === index;
tab.setAttribute('aria-selected', on ? 'true' : 'false');
tab.tabIndex = on ? 0 : -1;
panels[i].hidden = !on;
});
if (focus) { tabs[index].focus(); }
}
list.addEventListener('click', function (e) {
var i = tabs.indexOf(e.target.closest('.wpide-tabs__tab'));
if (i > -1) { select(i, false); }
});
list.addEventListener('keydown', function (e) {
var i = tabs.indexOf(document.activeElement), n = tabs.length;
if (i < 0) { return; }
if (e.key === 'ArrowRight') { select((i + 1) % n, true); }
else if (e.key === 'ArrowLeft') { select((i - 1 + n) % n, true); }
else if (e.key === 'Home') { select(0, true); }
else if (e.key === 'End') { select(n - 1, true); }
else { return; }
e.preventDefault();
});
wrap.insertBefore(list, panels[0]);
select(0, false);
});
JS
);
} );
add_shortcode( 'wpide_tabs', function ( $atts, $content = '' ) {
wp_enqueue_style( 'wpide-tabs' );
wp_enqueue_script( 'wpide-tabs' );
return '<div class="wpide-tabs">' . do_shortcode( shortcode_unautop( trim( $content ) ) ) . '</div>';
} );
add_shortcode( 'wpide_tab', function ( $atts, $content = '' ) {
$atts = shortcode_atts( array( 'title' => 'Tab' ), $atts, 'wpide_tab' );
return sprintf(
'<div class="wpide-tabs__panel" id="%1$s" data-title="%2$s">%3$s</div>',
esc_attr( 'wpide-tab-' . wp_unique_id() ),
esc_attr( $atts['title'] ),
wp_kses_post( wpautop( do_shortcode( trim( $content ) ) ) )
);
} );
Notes
Example: [wpide_tabs][wpide_tab title="Overview"]Text[/wpide_tab][wpide_tab title="Specs"]Text[/wpide_tab][/wpide_tabs]. Without JavaScript all panels simply show one after another.
How to add this snippet
- Install WPIDE on your WordPress site (it is free) and open Code Snippets.
- Use snippet above adds it from the library in one click. Or copy the code into a new snippet with the same code type.
- It is added inactive: review the code and settings, then switch it on.