Make WordPress Core

Changeset 60040


Ignore:
Timestamp:
03/18/2025 02:39:38 PM (6 weeks ago)
Author:
joedolson
Message:

Bundled Themes: A11y: Dismiss submenus with esc in Twenty Twenty.

Allow submenus in Twenty Twenty to be dismissed using the esc key to meet WCAG 1.4.13. Set focus to previous submenu parent on esc, and ensure that after escaping the last submenu, tab moves to the next parent item, not back into the submenu.

Props lcarevic, rcreators, pratiklondhe, poena, karmatosed, chaion07, audrasjb, mehdi01, mohonchandra, najmulsaju, saurabhdhariwal, ugyensupport, shailu25.
Fixes #49950.

Location:
trunk/src/wp-content/themes/twentytwenty
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-content/themes/twentytwenty/assets/js/index.js

    r57987 r60040  
    439439        links = menu.getElementsByTagName( 'a' );
    440440
    441         // Each time a menu link is focused or blurred, toggle focus.
     441        // Each time a menu link is focused, update focus.
    442442        for ( i = 0, len = links.length; i < len; i++ ) {
    443             links[i].addEventListener( 'focus', toggleFocus, true );
    444             links[i].addEventListener( 'blur', toggleFocus, true );
    445         }
    446 
    447         //Sets or removes the .focus class on an element.
    448         function toggleFocus() {
     443            links[i].addEventListener( 'focus', updateFocus, true );
     444        }
     445
     446        menu.addEventListener( 'focusout', removeFocus, true );
     447
     448        // Remove focus classes from menu.
     449        function removeFocus(e){
     450            const leavingMenu = ! menu.contains( e.relatedTarget );
     451
     452            if ( leavingMenu ) {
     453                // Remove focus from all li elements of primary-menu.
     454                menu.querySelectorAll( 'li' ).forEach( function( el ) {
     455                    if ( el.classList.contains( 'focus' ) ) {
     456                        el.classList.remove( 'focus', 'closed' );
     457                    }
     458                });
     459            }
     460        }
     461
     462        // Update focus class on an element.
     463        function updateFocus() {
    449464            var self = this;
    450465
    451             // Move up through the ancestors of the current link until we hit .primary-menu.
    452             while ( -1 === self.className.indexOf( 'primary-menu' ) ) {
    453                 // On li elements toggle the class .focus.
    454                 if ( 'li' === self.tagName.toLowerCase() ) {
    455                     if ( -1 !== self.className.indexOf( 'focus' ) ) {
    456                         self.className = self.className.replace( ' focus', '' );
     466            // Remove focus from all li elements of primary-menu.
     467            menu.querySelectorAll( 'li' ).forEach( function( el ){
     468                if ( el.classList.contains( 'closed' ) ) {
     469                    el.classList.remove( 'closed' );
     470                }
     471                if ( el.classList.contains( 'focus' ) ) {
     472                    el.classList.remove( 'focus' );
     473                }
     474            });
     475           
     476            // Set focus on current `a` element's parent `li`.
     477            self.parentElement.classList.add( 'focus' );
     478            // If current element is inside sub-menu find main parent li and add focus.
     479            if ( self.closest( '.menu-item-has-children' ) ) {
     480                twentytwentyFindParents( self, 'li.menu-item-has-children' ).forEach( function( element ) {
     481                    element.classList.add( 'focus' );
     482                });
     483            }
     484        }
     485
     486        // When the `esc` key is pressed while in menu, move focus up one level.
     487        menu.addEventListener( 'keydown', removeFocusEsc, true );
     488
     489        // Remove focus when `esc` key pressed.
     490        function removeFocusEsc( e ) {
     491            e = e || window.event;
     492            var isEscape = false,
     493                focusedElement = e.target;
     494
     495            // Find if pressed key is `esc`.
     496            if ( 'key' in e ) {
     497                isEscape = ( e.key === 'Escape' || e.key === 'Esc' );
     498            } else {
     499                isEscape = ( e.keyCode === 27 );
     500            }
     501
     502            // If pressed key is esc, remove focus class from parent menu li.
     503            if ( isEscape ) {
     504                var parentLi = focusedElement.closest( 'li' ),
     505                    nestedParent = closestExcludingSelf( parentLi, 'li.menu-item-has-children' ),
     506                    focusPosition = nestedParent ? nestedParent.querySelector('a') : false;
     507
     508                    if ( null !== nestedParent ) {
     509                        nestedParent.classList.add( 'focus' );
     510                        focusPosition.focus();
    457511                    } else {
    458                         self.className += ' focus';
    459                     }
    460                 }
    461                 self = self.parentElement;
    462             }
     512                        parentLi.classList.remove( 'focus' );
     513                        parentLi.classList.add( 'closed' );
     514                    }
     515            }
     516        }
     517
     518        function closestExcludingSelf(element, selector) {
     519            if ( ! element || ! selector ) {
     520                return null;
     521            }
     522            const parent = element.parentElement;
     523
     524            return parent ? parent.closest(selector) : null;
    463525        }
    464526    }
  • trunk/src/wp-content/themes/twentytwenty/style-rtl.css

    r59832 r60040  
    16771677}
    16781678
     1679.primary-menu .closed ul {
     1680    display: none;
     1681}
     1682
    16791683.primary-menu li.menu-item-has-children:hover > ul,
    16801684.primary-menu li.menu-item-has-children:focus > ul,
  • trunk/src/wp-content/themes/twentytwenty/style.css

    r59832 r60040  
    16831683}
    16841684
     1685.primary-menu .closed ul {
     1686    display: none;
     1687}
     1688
    16851689.primary-menu li.menu-item-has-children:hover > ul,
    16861690.primary-menu li.menu-item-has-children:focus > ul,
Note: See TracChangeset for help on using the changeset viewer.