Skip to content

Instantly share code, notes, and snippets.

@EarthmanWeb
Last active July 18, 2024 00:42
Show Gist options
  • Save EarthmanWeb/db03416e2ca48769b61bfbda12e17135 to your computer and use it in GitHub Desktop.
Save EarthmanWeb/db03416e2ca48769b61bfbda12e17135 to your computer and use it in GitHub Desktop.
Fixes WCAG Accessibility issues with Getwid Accordion to make it work with the tab key
<?php
/**
* Plugin Name: Accordion Accessibility Enhancements
* Description: Adds tab-index enhancements to Getwid accordion items for better accessibility.
* Version: 1.16
* Author: Terrance Orletsky / ChatGPT
*/
function em_add_inline_js_to_footer() {
?>
<script type="text/javascript" id="getwid-wcag">
document.addEventListener('DOMContentLoaded', function() {
jQuery(document).ready(function() {
// Find all the top-level accordion items and set their tab-index to 0
jQuery('.wp-block-getwid-accordion__header-wrapper').attr('tabindex', 0);
// Add role="button" to the '.wp-block-getwid-accordion__header-wrapper a' element:
// This ensures that the link is recognized as a button for accessibility purposes.
jQuery('.wp-block-getwid-accordion__header-wrapper a').attr('role', 'button');
// Add aria-controls="ui-id-2" and aria-expanded="false" to the <a> element:
// This associates the button with the content panel and indicates that the panel is initially collapsed.
jQuery('.wp-block-getwid-accordion__header-wrapper a').attr('aria-controls', function(index) {
return 'ui-id-' + (index + 2);
});
jQuery('.wp-block-getwid-accordion__header-wrapper a').attr('style', function(index) {
return 'min-height: 24px;min-width: 24px;';
});
// fix WCAG issue: An element with a role that makes its children presentational should not contain focusable elements.
jQuery('.wp-block-getwid-accordion__header-wrapper a').attr('tabindex', "-1");
// Add role="tabpanel" to the content wrapper: This identifies the content panel as a tab panel.
jQuery('.wp-block-getwid-accordion__content-wrapper').attr('role', 'tabpanel');
// Don't add tabindex to these elements
const emExcludeElements = 'p,div,span,strong,ul,ol,li,em,br';
// Find all elements inside each tab and set their tab-index to -1
jQuery('.wp-block-getwid-accordion__content-wrapper').each(function() {
// todo - this should be more selective to only target elements that are focusable
jQuery(this).find('*').not(emExcludeElements).attr('tabindex', -1);
});
// Do the same for any nested elements inside an iframe
jQuery('.wp-block-getwid-accordion__content-wrapper iframe').each(function() {
// todo - this should be more selective to only target elements that are focusable
jQuery(this).contents().find('*').not(emExcludeElements).attr('tabindex', -1);
});
// add click events so that the tabindex will be removed when the accordion is clicked,
// and added back when the accordion is closed, note that the content wrapper and header are siblings
// only do this for the contents of the adjacent one
// also bind this to work when the link is selected using the keyboard
jQuery('.wp-block-getwid-accordion__header-wrapper').on('click keydown', function(event) {
if (event.type === 'click' || (event.type === 'keydown' && event.key != 'Tab' && event.key != 'Shift')) {
// override getwid code (really?!) that is setting the rest of the accordion headers to -1 on click
jQuery('.wp-block-getwid-accordion__header-wrapper').attr('tabindex', 0);
//check for 'aria-expanded="true"' in this string: jQuery(this)[0]
// note: this check's logic is reversed because it updates after the click
if(jQuery(this)[0].outerHTML.includes('aria-expanded="true"')) {
// opened
// scroll the anchor to the top of the viewport after a tiny delay to allow the accordion to fully expand
setTimeout(() => {
jQuery(this).find('a')[0].scrollIntoView({behavior: 'smooth', block: 'start'});
}, 500);
// check that the accordion is closed
// add the tabindex back to all elements inside the content wrapper
jQuery(this).next('.wp-block-getwid-accordion__content-wrapper').find('*').not(emExcludeElements).attr('tabindex', 0);
// do the same for any nested elements inside an iframe
jQuery(this).next('.wp-block-getwid-accordion__content-wrapper').find('iframe').each(function() {
jQuery(this).contents().find('*').not(emExcludeElements).attr('tabindex', 0);
});
} else {
// closed
// remove the tabindex from all elements inside the content wrapper
jQuery(this).next('.wp-block-getwid-accordion__content-wrapper').find('*').not(emExcludeElements).attr('tabindex', -1);
// do the same for any nested elements inside an iframe
jQuery(this).next('.wp-block-getwid-accordion__content-wrapper').find('iframe').each(function() {
jQuery(this).contents().find('*').not(excludeElements).attr('tabindex', -1);
});
}
}
});
});
});
</script>
<?php
}
add_action( 'wp_footer', 'em_add_inline_js_to_footer', 2000 );
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment