Administration: A11y: Fix accordion accessibility.

Change accordions in the customizer and the navigation menus to make proper usage of accordion markup patterns. This includes adding missing `:focus` states, using a `button` element to control tabbing and interaction, instead of the heading elements, and removing instructional text for screen reader users that was used to compensate for the incorrect markup pattern.

Props afercia, rishishah, kushang78, rcreators, krupajnanda, hmbashar, joedolson.
Fixes #42002.
Built from https://develop.svn.wordpress.org/trunk@59224


git-svn-id: http://core.svn.wordpress.org/trunk@58616 1a063a9b-81f0-0310-95a4-ce76da25c4cd
This commit is contained in:
joedolson 2024-10-13 19:09:12 +00:00
parent c0dc2960e4
commit f7fb13a3c4
24 changed files with 188 additions and 138 deletions

View File

@ -2432,8 +2432,42 @@ h1.nav-tab-wrapper, /* Back-compat for pre-4.4 */
/* Back-compat for nav-menus screen */
.nav-menus-php .metabox-holder h3 {
padding: 0;
}
.nav-menus-php .metabox-holder .accordion-section-title button.accordion-trigger {
background: inherit;
color: #1d2327;
display: block;
position: relative;
text-align: right;
width: 100%;
outline: none;
border: 0;
padding: 10px 14px 11px 10px;
line-height: 1.5;
cursor: pointer;
}
.nav-menus-php .metabox-holder .accordion-section-title button.accordion-trigger:focus {
box-shadow: 0 0 0 2px #2271b1;
outline: 2px solid transparent;
}
.nav-menus-php .metabox-holder .accordion-section-title span.dashicons.dashicons-arrow-down {
position: absolute;
left: 10px;
right: auto;
color: #787c82;
border-radius: 50px;
}
.nav-menus-php .metabox-holder .accordion-section-title:hover span.dashicons.dashicons-arrow-down {
color: #1d2327;
}
.nav-menus-php .metabox-holder .accordion-section-title span.dashicons.dashicons-arrow-down::before {
position: relative;
right: -1px
}
.nav-menus-php .metabox-holder .accordion-section.open .accordion-section-title span.dashicons.dashicons-arrow-down {
transform: rotate(-180deg);
}
#templateside ul li a {
@ -3523,9 +3557,9 @@ img {
/* @todo: can we use a common class for these? */
.nav-menus-php .item-edit:before,
.widget-top .widget-action .toggle-indicator:before,
.control-section .accordion-section-title:after,
.accordion-section-title:after {
.wp-customizer .control-section .accordion-section-title:after,
.wp-customizer .accordion-section-title:after,
.widget-top .widget-action .toggle-indicator:before {
content: "\f140";
font: normal 20px/1 dashicons;
speak: never;
@ -3543,8 +3577,7 @@ img {
.handlediv,
.postbox .handlediv.button-link,
.item-edit,
.toggle-indicator,
.accordion-section-title:after {
.toggle-indicator {
color: #787c82;
}
@ -3560,8 +3593,7 @@ img {
.postbox .handlediv.button-link:focus,
.item-edit:hover,
.item-edit:focus,
.sidebar-name:hover .toggle-indicator,
.accordion-section-title:hover:after {
.sidebar-name:hover .toggle-indicator {
color: #1d2327;
/* Only visible in Windows High Contrast mode */
outline: 2px solid transparent;
@ -3573,14 +3605,6 @@ img {
outline: 2px solid transparent;
}
.control-section .accordion-section-title:after,
.accordion-section-title:after {
float: left;
left: 20px;
top: -2px;
}
.control-section.open .accordion-section-title:after,
#customize-info.open .accordion-section-title:after,
.nav-menus-php .menu-item-edit-active .item-edit:before,
.widget.open .widget-top .widget-action .toggle-indicator:before,
@ -3970,6 +3994,10 @@ img {
padding: 12px;
}
.nav-menus-php .metabox-holder h3 {
padding: 0;
}
.postbox .handlediv {
margin-top: 3px;
}

File diff suppressed because one or more lines are too long

View File

@ -2431,8 +2431,42 @@ h1.nav-tab-wrapper, /* Back-compat for pre-4.4 */
/* Back-compat for nav-menus screen */
.nav-menus-php .metabox-holder h3 {
padding: 0;
}
.nav-menus-php .metabox-holder .accordion-section-title button.accordion-trigger {
background: inherit;
color: #1d2327;
display: block;
position: relative;
text-align: left;
width: 100%;
outline: none;
border: 0;
padding: 10px 10px 11px 14px;
line-height: 1.5;
cursor: pointer;
}
.nav-menus-php .metabox-holder .accordion-section-title button.accordion-trigger:focus {
box-shadow: 0 0 0 2px #2271b1;
outline: 2px solid transparent;
}
.nav-menus-php .metabox-holder .accordion-section-title span.dashicons.dashicons-arrow-down {
position: absolute;
right: 10px;
left: auto;
color: #787c82;
border-radius: 50px;
}
.nav-menus-php .metabox-holder .accordion-section-title:hover span.dashicons.dashicons-arrow-down {
color: #1d2327;
}
.nav-menus-php .metabox-holder .accordion-section-title span.dashicons.dashicons-arrow-down::before {
position: relative;
left: -1px
}
.nav-menus-php .metabox-holder .accordion-section.open .accordion-section-title span.dashicons.dashicons-arrow-down {
transform: rotate(180deg);
}
#templateside ul li a {
@ -3522,9 +3556,9 @@ img {
/* @todo: can we use a common class for these? */
.nav-menus-php .item-edit:before,
.widget-top .widget-action .toggle-indicator:before,
.control-section .accordion-section-title:after,
.accordion-section-title:after {
.wp-customizer .control-section .accordion-section-title:after,
.wp-customizer .accordion-section-title:after,
.widget-top .widget-action .toggle-indicator:before {
content: "\f140";
font: normal 20px/1 dashicons;
speak: never;
@ -3542,8 +3576,7 @@ img {
.handlediv,
.postbox .handlediv.button-link,
.item-edit,
.toggle-indicator,
.accordion-section-title:after {
.toggle-indicator {
color: #787c82;
}
@ -3559,8 +3592,7 @@ img {
.postbox .handlediv.button-link:focus,
.item-edit:hover,
.item-edit:focus,
.sidebar-name:hover .toggle-indicator,
.accordion-section-title:hover:after {
.sidebar-name:hover .toggle-indicator {
color: #1d2327;
/* Only visible in Windows High Contrast mode */
outline: 2px solid transparent;
@ -3572,14 +3604,6 @@ img {
outline: 2px solid transparent;
}
.control-section .accordion-section-title:after,
.accordion-section-title:after {
float: right;
right: 20px;
top: -2px;
}
.control-section.open .accordion-section-title:after,
#customize-info.open .accordion-section-title:after,
.nav-menus-php .menu-item-edit-active .item-edit:before,
.widget.open .widget-top .widget-action .toggle-indicator:before,
@ -3969,6 +3993,10 @@ img {
padding: 12px;
}
.nav-menus-php .metabox-holder h3 {
padding: 0;
}
.postbox .handlediv {
margin-top: 3px;
}

File diff suppressed because one or more lines are too long

View File

@ -554,6 +554,23 @@ body.trashing #publish-settings {
.15s border-color ease-in-out;
}
.accordion-section-title:has(button.accordion-trigger) {
padding: 0;
}
.accordion-section-title button.accordion-trigger {
all: unset;
width: 100%;
height: 100%;
padding: 10px 14px 11px 10px;
display: flex;
align-items: center;
}
.accordion-section-title button.accordion-trigger:has(.menu-in-location) {
display: block;
}
@media (prefers-reduced-motion: reduce) {
#customize-theme-controls .accordion-section-title,
#customize-outer-theme-controls .accordion-section-title {
@ -580,9 +597,9 @@ body.trashing #publish-settings {
}
#customize-controls .control-section:hover > .accordion-section-title,
#customize-controls .control-section .accordion-section-title:hover,
#customize-controls .control-section .accordion-section-title button:hover,
#customize-controls .control-section.open .accordion-section-title,
#customize-controls .control-section .accordion-section-title:focus {
#customize-controls .control-section .accordion-section-title button:focus {
color: #2271b1;
background: #f6f7f7;
border-right-color: #2271b1;

File diff suppressed because one or more lines are too long

View File

@ -553,6 +553,23 @@ body.trashing #publish-settings {
.15s border-color ease-in-out;
}
.accordion-section-title:has(button.accordion-trigger) {
padding: 0;
}
.accordion-section-title button.accordion-trigger {
all: unset;
width: 100%;
height: 100%;
padding: 10px 10px 11px 14px;
display: flex;
align-items: center;
}
.accordion-section-title button.accordion-trigger:has(.menu-in-location) {
display: block;
}
@media (prefers-reduced-motion: reduce) {
#customize-theme-controls .accordion-section-title,
#customize-outer-theme-controls .accordion-section-title {
@ -579,9 +596,9 @@ body.trashing #publish-settings {
}
#customize-controls .control-section:hover > .accordion-section-title,
#customize-controls .control-section .accordion-section-title:hover,
#customize-controls .control-section .accordion-section-title button:hover,
#customize-controls .control-section.open .accordion-section-title,
#customize-controls .control-section .accordion-section-title:focus {
#customize-controls .control-section .accordion-section-title button:focus {
color: #2271b1;
background: #f6f7f7;
border-left-color: #2271b1;

File diff suppressed because one or more lines are too long

View File

@ -543,8 +543,9 @@
background: transparent;
}
#available-menu-items .accordion-section-title button {
display: block;
#available-menu-items .accordion-section-title button .toggle-indicator {
display: flex;
align-items: center;
width: 28px;
height: 35px;
position: absolute;

File diff suppressed because one or more lines are too long

View File

@ -542,8 +542,9 @@
background: transparent;
}
#available-menu-items .accordion-section-title button {
display: block;
#available-menu-items .accordion-section-title button .toggle-indicator {
display: flex;
align-items: center;
width: 28px;
height: 35px;
position: absolute;

File diff suppressed because one or more lines are too long

View File

@ -1567,22 +1567,23 @@ function do_accordion_sections( $screen, $context, $data_object ) {
$hidden_class = in_array( $box['id'], $hidden, true ) ? 'hide-if-js' : '';
$open_class = '';
$aria_expanded = 'false';
if ( ! $first_open && empty( $hidden_class ) ) {
$first_open = true;
$open_class = 'open';
$aria_expanded = 'true';
}
?>
<li class="control-section accordion-section <?php echo $hidden_class; ?> <?php echo $open_class; ?> <?php echo esc_attr( $box['id'] ); ?>" id="<?php echo esc_attr( $box['id'] ); ?>">
<h3 class="accordion-section-title hndle" tabindex="0">
<h3 class="accordion-section-title hndle">
<button type="button" class="accordion-trigger" aria-expanded="<?php echo $aria_expanded; ?>" aria-controls="<?php echo esc_attr( $box['id'] ); ?>-content">
<span class="accordion-title">
<?php echo esc_html( $box['title'] ); ?>
<span class="screen-reader-text">
<?php
/* translators: Hidden accessibility text. */
_e( 'Press return or enter to open this section' );
?>
<span class="dashicons dashicons-arrow-down" aria-hidden="true"></span>
</span>
</button>
</h3>
<div class="accordion-section-content <?php postbox_classes( $box['id'], $page ); ?>">
<div class="accordion-section-content <?php postbox_classes( $box['id'], $page ); ?>" id="<?php echo esc_attr( $box['id'] ); ?>-content">
<div class="inside">
<?php call_user_func( $box['callback'], $data_object, $box ); ?>
</div><!-- .inside -->

View File

@ -7,18 +7,18 @@
*
* <div class="accordion-container">
* <div class="accordion-section open">
* <h3 class="accordion-section-title"></h3>
* <div class="accordion-section-content">
* <h3 class="accordion-section-title"><button type="button" aria-expanded="true" aria-controls="target-1"></button></h3>
* <div class="accordion-section-content" id="target">
* </div>
* </div>
* <div class="accordion-section">
* <h3 class="accordion-section-title"></h3>
* <div class="accordion-section-content">
* <h3 class="accordion-section-title"><button type="button" aria-expanded="false" aria-controls="target-2"></button></h3>
* <div class="accordion-section-content" id="target-2">
* </div>
* </div>
* <div class="accordion-section">
* <h3 class="accordion-section-title"></h3>
* <div class="accordion-section-content">
* <h3 class="accordion-section-title"><button type="button" aria-expanded="false" aria-controls="target-3"></button></h3>
* <div class="accordion-section-content" id="target-3">
* </div>
* </div>
* </div>
@ -34,13 +34,7 @@
$( function () {
// Expand/Collapse accordion sections on click.
$( '.accordion-container' ).on( 'click keydown', '.accordion-section-title', function( e ) {
if ( e.type === 'keydown' && 13 !== e.which ) { // "Return" key.
return;
}
e.preventDefault(); // Keep this AFTER the key filter above.
$( '.accordion-container' ).on( 'click', '.accordion-section-title button', function() {
accordionSwitch( $( this ) );
});
@ -54,7 +48,6 @@
*/
function accordionSwitch ( el ) {
var section = el.closest( '.accordion-section' ),
sectionToggleControl = section.find( '[aria-expanded]' ).first(),
container = section.closest( '.accordion-container' ),
siblings = container.find( '.open' ),
siblingsToggleControl = siblings.find( '[aria-expanded]' ).first(),
@ -86,8 +79,8 @@
}, 150);
// If there's an element with an aria-expanded attribute, assume it's a toggle control and toggle the aria-expanded value.
if ( sectionToggleControl ) {
sectionToggleControl.attr( 'aria-expanded', String( sectionToggleControl.attr( 'aria-expanded' ) === 'false' ) );
if ( el ) {
el.attr( 'aria-expanded', String( el.attr( 'aria-expanded' ) === 'false' ) );
}
}

View File

@ -1,2 +1,2 @@
/*! This file is auto-generated */
!function(s){s(function(){s(".accordion-container").on("click keydown",".accordion-section-title",function(e){var n,o,a,i,t;"keydown"===e.type&&13!==e.which||(e.preventDefault(),e=(e=s(this)).closest(".accordion-section"),n=e.find("[aria-expanded]").first(),o=e.closest(".accordion-container"),a=o.find(".open"),i=a.find("[aria-expanded]").first(),t=e.find(".accordion-section-content"),e.hasClass("cannot-expand"))||(o.addClass("opening"),e.hasClass("open")?(e.toggleClass("open"),t.toggle(!0).slideToggle(150)):(i.attr("aria-expanded","false"),a.removeClass("open"),a.find(".accordion-section-content").show().slideUp(150),t.toggle(!1).slideToggle(150),e.toggleClass("open")),setTimeout(function(){o.removeClass("opening")},150),n&&n.attr("aria-expanded",String("false"===n.attr("aria-expanded"))))})})}(jQuery);
!function(s){s(function(){s(".accordion-container").on("click",".accordion-section-title button",function(){var n,o,e,a,t,i;n=s(this),o=n.closest(".accordion-section"),e=o.closest(".accordion-container"),a=e.find(".open"),t=a.find("[aria-expanded]").first(),i=o.find(".accordion-section-content"),o.hasClass("cannot-expand")||(e.addClass("opening"),o.hasClass("open")?(o.toggleClass("open"),i.toggle(!0).slideToggle(150)):(t.attr("aria-expanded","false"),a.removeClass("open"),a.find(".accordion-section-content").show().slideUp(150),i.toggle(!1).slideToggle(150),o.toggleClass("open")),setTimeout(function(){e.removeClass("opening")},150),n&&n.attr("aria-expanded",String("false"===n.attr("aria-expanded"))))})})}(jQuery);

View File

@ -1530,7 +1530,7 @@
}
// Expand/Collapse accordion sections on click.
section.container.find( '.accordion-section-title, .customize-section-back' ).on( 'click keydown', function( event ) {
section.container.find( '.accordion-section-title button, .customize-section-back' ).on( 'click keydown', function( event ) {
if ( api.utils.isKeydownButNotEnterEvent( event ) ) {
return;
}
@ -1605,7 +1605,7 @@
content = section.contentContainer,
overlay = section.headContainer.closest( '.wp-full-overlay' ),
backBtn = content.find( '.customize-section-back' ),
sectionTitle = section.headContainer.find( '.accordion-section-title' ).first(),
sectionTitle = section.headContainer.find( '.accordion-section-title button' ).first(),
expand, panel;
if ( expanded && ! content.hasClass( 'open' ) ) {
@ -1615,9 +1615,6 @@
} else {
expand = function() {
section._animateChangeExpanded( function() {
sectionTitle.attr( 'tabindex', '-1' );
backBtn.attr( 'tabindex', '0' );
backBtn.trigger( 'focus' );
content.css( 'top', '' );
container.scrollTop( 0 );
@ -1663,8 +1660,6 @@
}
}
section._animateChangeExpanded( function() {
backBtn.attr( 'tabindex', '-1' );
sectionTitle.attr( 'tabindex', '0' );
sectionTitle.trigger( 'focus' );
content.css( 'top', '' );
@ -2699,7 +2694,7 @@
container = section.headContainer.closest( '.wp-full-overlay-sidebar-content' ),
content = section.contentContainer,
backBtn = content.find( '.customize-section-back' ),
sectionTitle = section.headContainer.find( '.accordion-section-title' ).first(),
sectionTitle = section.headContainer.find( '.accordion-section-title button' ).first(),
body = $( document.body ),
expand, panel;
@ -2719,9 +2714,6 @@
} else {
expand = function() {
section._animateChangeExpanded( function() {
sectionTitle.attr( 'tabindex', '-1' );
backBtn.attr( 'tabindex', '0' );
backBtn.trigger( 'focus' );
content.css( 'top', '' );
container.scrollTop( 0 );
@ -2752,8 +2744,6 @@
}
}
section._animateChangeExpanded( function() {
backBtn.attr( 'tabindex', '-1' );
sectionTitle.attr( 'tabindex', '0' );
sectionTitle.trigger( 'focus' );
content.css( 'top', '' );
@ -2843,7 +2833,7 @@
var meta, panel = this;
// Expand/Collapse accordion sections on click.
panel.headContainer.find( '.accordion-section-title' ).on( 'click keydown', function( event ) {
panel.headContainer.find( '.accordion-section-title button' ).on( 'click keydown', function( event ) {
if ( api.utils.isKeydownButNotEnterEvent( event ) ) {
return;
}
@ -2947,7 +2937,7 @@
accordionSection = panel.contentContainer,
overlay = accordionSection.closest( '.wp-full-overlay' ),
container = accordionSection.closest( '.wp-full-overlay-sidebar-content' ),
topPanel = panel.headContainer.find( '.accordion-section-title' ),
topPanel = panel.headContainer.find( '.accordion-section-title button' ),
backBtn = accordionSection.find( '.customize-panel-back' ),
childSections = panel.sections(),
skipTransition;
@ -2974,9 +2964,6 @@
} );
} else {
panel._animateChangeExpanded( function() {
topPanel.attr( 'tabindex', '-1' );
backBtn.attr( 'tabindex', '0' );
backBtn.trigger( 'focus' );
accordionSection.css( 'top', '' );
container.scrollTop( 0 );
@ -2996,8 +2983,6 @@
skipTransition = accordionSection.hasClass( 'skip-transition' );
if ( ! skipTransition ) {
panel._animateChangeExpanded( function() {
topPanel.attr( 'tabindex', '0' );
backBtn.attr( 'tabindex', '-1' );
topPanel.focus();
accordionSection.css( 'top', '' );

File diff suppressed because one or more lines are too long

View File

@ -1107,7 +1107,7 @@
var section = this,
$title;
$title = section.container.find( '.accordion-section-title:first' );
$title = section.container.find( '.accordion-section-title button:first' );
$title.find( '.menu-in-location' ).remove();
_.each( themeLocationSlugs, function( themeLocationSlug ) {
var $label, locationName;

File diff suppressed because one or more lines are too long

View File

@ -1223,20 +1223,14 @@ final class WP_Customize_Nav_Menus {
?>
<div id="<?php echo esc_attr( $id ); ?>" class="accordion-section">
<h4 class="accordion-section-title" role="presentation">
<button type="button" class="accordion-trigger" aria-expanded="false" aria-controls="<?php echo esc_attr( $id ); ?>-content">
<?php echo esc_html( $available_item_type['title'] ); ?>
<span class="spinner"></span>
<span class="no-items"><?php _e( 'No items' ); ?></span>
<button type="button" class="button-link" aria-expanded="false">
<span class="screen-reader-text">
<?php
/* translators: %s: Title of a section with menu items. */
printf( __( 'Toggle section: %s' ), esc_html( $available_item_type['title'] ) );
?>
</span>
<span class="toggle-indicator" aria-hidden="true"></span>
</button>
</h4>
<div class="accordion-section-content">
<div class="accordion-section-content" id="<?php echo esc_attr( $id ); ?>-content">
<?php if ( 'post_type' === $available_item_type['type'] ) : ?>
<?php $post_type_obj = get_post_type_object( $available_item_type['object'] ); ?>
<?php if ( current_user_can( $post_type_obj->cap->create_posts ) && current_user_can( $post_type_obj->cap->publish_posts ) ) : ?>
@ -1264,18 +1258,12 @@ final class WP_Customize_Nav_Menus {
?>
<div id="new-custom-menu-item" class="accordion-section">
<h4 class="accordion-section-title" role="presentation">
<button type="button" class="accordion-trigger" aria-expanded="false" aria-controls="new-custom-menu-item-content">
<?php _e( 'Custom Links' ); ?>
<button type="button" class="button-link" aria-expanded="false">
<span class="screen-reader-text">
<?php
/* translators: Hidden accessibility text. */
_e( 'Toggle section: Custom Links' );
?>
</span>
<span class="toggle-indicator" aria-hidden="true"></span>
</button>
</h4>
<div class="accordion-section-content customlinkdiv">
<div class="accordion-section-content customlinkdiv" id="new-custom-menu-item-content">
<input type="hidden" value="custom" id="custom-menu-item-type" name="menu-item[-1][menu-item-type]" />
<p id="menu-item-url-wrap" class="wp-clearfix">
<label class="howto" for="custom-menu-item-url"><?php _e( 'URL' ); ?></label>

View File

@ -346,16 +346,12 @@ class WP_Customize_Panel {
protected function render_template() {
?>
<li id="accordion-panel-{{ data.id }}" class="accordion-section control-section control-panel control-panel-{{ data.type }}">
<h3 class="accordion-section-title" tabindex="0">
<h3 class="accordion-section-title">
<button type="button" class="accordion-trigger" aria-expanded="false" aria-controls="{{ data.id }}-content">
{{ data.title }}
<span class="screen-reader-text">
<?php
/* translators: Hidden accessibility text. */
_e( 'Press return or enter to open this panel' );
?>
</span>
</button>
</h3>
<ul class="accordion-sub-container control-panel-content"></ul>
<ul class="accordion-sub-container control-panel-content" id="{{ data.id }}-content"></ul>
</li>
<?php
}

View File

@ -355,16 +355,12 @@ class WP_Customize_Section {
protected function render_template() {
?>
<li id="accordion-section-{{ data.id }}" class="accordion-section control-section control-section-{{ data.type }}">
<h3 class="accordion-section-title" tabindex="0">
<h3 class="accordion-section-title">
<button type="button" class="accordion-trigger" aria-expanded="false" aria-controls="{{ data.id }}-content">
{{ data.title }}
<span class="screen-reader-text">
<?php
/* translators: Hidden accessibility text. */
_e( 'Press return or enter to open this section' );
?>
</span>
</button>
</h3>
<ul class="accordion-section-content">
<ul class="accordion-section-content" id="{{ data.id }}-content">
<li class="customize-section-description-container section-meta <# if ( data.description_hidden ) { #>customize-info<# } #>">
<div class="customize-section-title">
<button class="customize-section-back" tabindex="-1">

View File

@ -44,7 +44,6 @@ class WP_Customize_Themes_Panel extends WP_Customize_Panel {
echo '<span class="customize-action">' . __( 'Previewing theme' ) . '</span> {{ data.title }}';
}
?>
<?php if ( current_user_can( 'switch_themes' ) ) : ?>
<button type="button" class="button change-theme" aria-label="<?php esc_attr_e( 'Change theme' ); ?>"><?php _ex( 'Change', 'theme' ); ?></button>
<?php endif; ?>

View File

@ -16,7 +16,7 @@
*
* @global string $wp_version
*/
$wp_version = '6.7-beta2-59223';
$wp_version = '6.7-beta2-59224';
/**
* Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.