Crocoblock / suggestions

The suggestions for CrocoBlock project
195 stars 79 forks source link

Accessible Filter Components in JetSmartFilter #4514

Open heroicP opened 2 years ago

heroicP commented 2 years ago

Can the filter controls be made more accessible. I had to overlay my own Javascript here to make the filters at the top keyboard and screen reader accessible.

https://www.prideindustries.com/news-and-insights/articles

Here's the code I have running on that page to make the filter checkbox buttons, dropdown filter and page navigation work.

var initialLoad = 1;
    var isFilter = 0;

    jQuery(document).ready(function () {

        setTimeout(function () {

            // Determine if checkbox/filter is checked on load and set the element attributes accordingly
            jQuery('.jet-checkboxes-list__input').each(
                function () {
                    if (jQuery(this).prop("checked") == true) {
                        jQuery(this).attr('aria-checked', 'true');
                        jQuery(this).parent().attr('aria-checked', 'true');
                    } else {
                        jQuery(this).attr('aria-checked', 'false');
                        jQuery(this).parent().attr('aria-checked', 'false');
                    }
                });

            //  Set initial attributes for everything
            jQuery('.jet-select__control').attr('role', 'listbox');
            jQuery('.jet-select__control').attr('aria-label', 'filter by topic');
            jQuery('.jet-checkboxes-list__item').attr('role', 'checkbox');
            jQuery('.jet-checkboxes-list__item').attr('tabindex', '0');
            jQuery('.jet-filters-pagination__item').attr('tabindex', '0');
            jQuery('.jet-checkboxes-list__item').attr('onclick', 'toggleFilter("click")');
            jQuery('.jet-checkboxes-list__item').attr('onkeydown', 'toggleFilter("keyboard")');
            jQuery('.jet-filters-pagination__item').attr('onkeydown', 'changePage()');

        }, 500);
    });

    //This code runs when a new "page" is loaded.
    jQuery(document).ajaxComplete(function () {

        //Don't run this code if this is just the initial page load
        if (initialLoad != 1) {

            //Don't run this code if the posts are being filtered
            if (isFilter != 1) {

                // get first article.entry
                // focus on article.entry .news-card-link
                jQuery('article.entry').first().find('.news-card-link').focus();
            } else {
                isFilter = 0;
            }

        } else {
            initialLoad = 0;
        }

        //Re-add attribute on listener to "page" navigation numbers
        setTimeout(function () {
            jQuery('.jet-filters-pagination__item').attr('tabindex', '0');
            jQuery('.jet-filters-pagination__item').attr('onkeydown', 'changePage()');
        }, 500);

    });

    // This function fires a click event when user presses enter on one of the page nav numbers
    function changePage() {

        var code = event.keyCode || event.which;

        if (code === 13) {
            event.preventDefault();
            event.target.click();
        }
    }

    // For keyboard users this function triggers the click event when they press enter or spacebar on a filter button
    // For mouse users this just sets all the attributes
    function toggleFilter(activator) {

        isFilter = 1;

        if (activator == 'click') {
            if (event.target.getAttribute('aria-checked') == 'false') {
                event.target.checked = true;
                event.target.setAttribute('aria-checked', 'true');
                event.target.parentNode.setAttribute('aria-checked', 'true');
                event.target.parentNode.parentNode.setAttribute('aria-checked', 'true');
            } else {
                event.target.checked = false;
                event.target.setAttribute('aria-checked', 'false');
                event.target.parentNode.setAttribute('aria-checked', 'false');
                event.target.parentNode.parentNode.setAttribute('aria-checked', 'false');
            };
        } else if (activator == 'keyboard') {

            var code = event.keyCode || event.which;

            if (code === 13 || code === 32) {
                event.preventDefault();
                event.target.click();

            }
        }

    }

I'm finding I basically need to add my own code to all the filter components to make them accessible so JetSmartFilters aren't really an out of the box solution for anyone who cares about accessibility.

chwebagency commented 2 years ago

@SargasTM I think is is very similar to the issues were running into in this thread on accessibility: https://github.com/Crocoblock/suggestions/issues/4284