edenspiekermann / a11y-toggle

A tiny script for accessible content toggles.
https://edenspiekermann.github.io/a11y-toggle/
MIT License
304 stars 21 forks source link

close when click outside #36

Closed hans2103 closed 2 years ago

hans2103 commented 2 years ago

In your example Connected toggles you describe how to close a toggle when opening another.

This can be used on close-all-when-click-outside-an-opened-toggle.

https://github.com/edenspiekermann/a11y-toggle/blob/486037dd084eea9a74ba5f449d65f5e7b95afba7/a11y-toggle.js#L33-L35

Replace return false with collapseAll (event) and all opened toggles will be closed when clicking outside an opened toggle.

Can you add the code from the example in the base of your a11y-toggle?

function collapse (toggle) {
  var id = toggle.getAttribute('data-a11y-toggle');
  var collapsibleBox = document.getElementById(id);
  collapsibleBox.setAttribute('aria-hidden', true);
  toggle.setAttribute('aria-expanded', false);
}

function collapseAll (event) {
  toggles
    .filter(function (toggle) {
      return toggle !== event.target;
    })
    .forEach(collapse);
}
hans2103 commented 2 years ago

sorry... my bad... cannot be used. the function getCLosestToggle only goes up in the tree to find the toggle button. The collapsibleBox is the nextElementSibling of the toggle button

A click outside the collapsilbeBox and not inside the toggle button, will never find the toggle button.

hans2103 commented 2 years ago

currently solved the issue with the following code in my setup:


if ('querySelector' in document && 'addEventListener' in window) {
    function getClosestToggle(element) {
        if (element.closest) {
            return element.closest('[data-a11y-toggle]');
        }

        while (element) {
            if (element.nodeType === 1 && element.hasAttribute('data-a11y-toggle')) {
                return element;
            }

            element = element.parentNode;
        }

        return null;
    }

    function getClosestToggleBox(element) {
        if (element.closest) {
            return element.closest('[data-a11y-toggle-box]');
        }

        while (element) {
            if (element.nodeType === 1 && element.hasAttribute('data-a11y-toggle-box')) {
                return element;
            }

            element = element.parentNode;
        }

        return null;
    }

    /**
     * Execute
     */
    (function () {
            const collapse = toggle => {
                const collapsibleBox = document.getElementById(toggle.getAttribute('data-a11y-toggle'));
                collapsibleBox.setAttribute('aria-hidden', true);
                toggle.setAttribute('aria-expanded', false);
            };

            const collapseAll = () => {
                toggles.forEach(collapse);
            };

            const toggles = Array.prototype.slice.call(
                document.querySelectorAll('[data-a11y-toggle]')
            );

            const closeWhenClickOutside = (event) => {
                let toggleBox = getClosestToggleBox(event.target),
                    toggle = getClosestToggle(event.target);

                if (toggleBox || toggle) {
                    return;
                }

                collapseAll(event);
            };

            document.addEventListener('click', event => {
                closeWhenClickOutside(event);
            });
        });
    }());
}