Skip to content

Commit 0f4d8e7

Browse files
authored
Merge pull request #311 from BeAPI/fix/header-accessibility
fix (header) : handle escape keyup, add aria attributes
2 parents 38261a5 + 5f615c6 commit 0f4d8e7

File tree

6 files changed

+57
-28
lines changed

6 files changed

+57
-28
lines changed

components/parts/common/header.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,9 @@
1010
</a>
1111

1212
<button class="header__menu-toggle" aria-expanded="false" aria-controls="menu">
13-
<span aria-hidden="true"></span>
14-
<span class="sr-only"><?php esc_html_e( 'Open/Close the menu', 'beapi-frontend-framework' ); ?></span>
13+
<span></span>
14+
<span class="sr-only aria-expanded-false-text"><?php esc_html_e( 'Open the menu', 'beapi-frontend-framework' ); ?></span>
15+
<span class="sr-only aria-expanded-true-text"><?php esc_html_e( 'Close the menu', 'beapi-frontend-framework' ); ?></span>
1516
</button>
1617

1718
<nav id="menu" class="header__menu" aria-label="<?php esc_attr_e( 'Main navigation', 'beapi-frontend-framework' ); ?>" role="navigation">

inc/Helpers/Custom_Menu_Walker.php

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,13 @@ public function start_el( &$output, $item, $depth = 0, $args = [], $id = 0 ) {
2121
parent::start_el( $output, $item, $depth, $args, $id );
2222

2323
if ( in_array( 'menu-item-has-children', $item->classes, true ) ) {
24-
$output .= '<button class="header__sub-menu-toggle" type="button"><span>' . esc_html__( 'Toggle menu', 'beapi-frontend-framework' ) . '</span></button>';
25-
$output .= '<div class="header__sub-menu header__sub-menu-level-' . $depth . '"><div>';
24+
$sub_menu_id = 'header-sub-menu-' . $item->ID;
25+
26+
$output .= '<button class="header__sub-menu-toggle" type="button" aria-expanded="false" aria-controls="' . esc_attr( $sub_menu_id ) . '">';
27+
$output .= sprintf( '<span class="aria-expanded-false-text">%s</span>', esc_html__( 'Open menu', 'beapi-frontend-framework' ) );
28+
$output .= sprintf( '<span class="aria-expanded-true-text">%s</span>', esc_html__( 'Close menu', 'beapi-frontend-framework' ) );
29+
$output .= '</button>';
30+
$output .= sprintf( '<div id="%s" class="header__sub-menu %s"><div>', esc_attr( $sub_menu_id ), esc_attr( 'header__sub-menu-level-' . $depth ) );
2631
$output .= '<ul>';
2732
}
2833
}

src/js/classes/Header.js

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
/* eslint-disable */
21
import AbstractDomElement from './AbstractDomElement'
32
import each from '../utils/each'
43
import { Tween } from 'oneloop.js'
@@ -86,6 +85,7 @@ class Header extends AbstractDomElement {
8685
}
8786

8887
openSubMenu(liParent) {
88+
const toggle = liParent.children[1]
8989
const subMenu = liParent.children[2]
9090
var childHeight
9191

@@ -96,6 +96,7 @@ class Header extends AbstractDomElement {
9696
childHeight = subMenu.children[0].offsetHeight
9797

9898
liParent.classList.add(this._settings.liSubMenuOpenedClass)
99+
toggle.setAttribute('aria-expanded', 'true')
99100

100101
new Tween({
101102
duration: 500,
@@ -112,6 +113,7 @@ class Header extends AbstractDomElement {
112113
}
113114

114115
closeSubMenu(liParent) {
116+
const toggle = liParent.children[1]
115117
const subMenu = liParent.children[2]
116118
const currentHeight = subMenu.offsetHeight
117119

@@ -120,6 +122,7 @@ class Header extends AbstractDomElement {
120122
subMenu.style.height = currentHeight
121123

122124
liParent.classList.remove(this._settings.liSubMenuOpenedClass)
125+
toggle.setAttribute('aria-expanded', 'false')
123126

124127
new Tween({
125128
duration: 500,
@@ -153,7 +156,16 @@ Header.defaults = {
153156
function onKeyup(e) {
154157
const activeElement = document.activeElement
155158

156-
if (e.keyCode === 9 && !activeElement.classList.contains('header__sub-menu-toggle')) {
159+
// escape
160+
if (e.keyCode === 27) {
161+
if (this._openedSubMenu && this._openedSubMenu.contains(activeElement)) {
162+
this.closeSubMenu(this._openedSubMenu.parentNode)
163+
} else if (this.isMenuOpen()) {
164+
this.closeMenu()
165+
}
166+
}
167+
// tab
168+
else if (e.keyCode === 9 && !activeElement.classList.contains('header__sub-menu-toggle')) {
157169
if (this._openedSubMenu && !this._openedSubMenu.contains(activeElement)) {
158170
this.closeSubMenu(this._openedSubMenu.parentNode)
159171
}
@@ -217,18 +229,18 @@ function onMouseLeaveLi(e) {
217229
clearTimeout(this._mouseTimers[li.id])
218230

219231
if (subMenu.style.display === 'block') {
220-
this._mouseTimers[li.id] = setTimeout(function () {
221-
that.closeSubMenu(li)
222-
}, isFirstLevel ? 1500 : 250)
232+
this._mouseTimers[li.id] = setTimeout(
233+
function () {
234+
that.closeSubMenu(li)
235+
},
236+
isFirstLevel ? 1500 : 250
237+
)
223238
}
224239
}
225240

226241
function onClickToggle() {
227242
this.toggleMenu()
228243
}
229-
// ----
230-
// utils
231-
// ----
232244

233245
// ----
234246
// init
@@ -238,4 +250,4 @@ Header.init('#header')
238250
// ----
239251
// export
240252
// ----
241-
export default Header
253+
export default Header

src/scss/04-utilities/_aria.scss

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
[aria-expanded="false"] {
2+
.aria-expanded-true-text {
3+
display: none !important;
4+
}
5+
}
6+
7+
[aria-expanded="true"] {
8+
.aria-expanded-false-text {
9+
display: none !important;
10+
}
11+
}

src/scss/04-utilities/utilities.scss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@
66
@import "./container";
77
@import "./sr-only";
88
@import "./js-animation";
9+
@import "./aria";

src/scss/08-template-parts/_header.scss

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -101,8 +101,8 @@
101101
}
102102

103103
.has-sub-menu-open {
104-
> #{$el}__sub-menu-toggle .icon {
105-
transform: rotate(180deg);
104+
> #{$el}__sub-menu-toggle::before {
105+
transform: translateY(-50%) rotate(225deg);
106106
}
107107
}
108108
}
@@ -116,20 +116,25 @@
116116
height: 50px;
117117
padding: 0;
118118
color: $color-dark;
119+
text-indent: -10000px;
119120
vertical-align: middle;
120121
cursor: pointer;
121122
background: none;
122123
border: none;
123124

124-
.icon {
125+
&::before {
125126
position: absolute;
126127
top: 50%;
127128
left: 50%;
128-
width: 10px;
129+
width: 6px;
129130
height: 6px;
130-
margin: -3px 0 0 -5px;
131-
fill: currentColor;
132-
transition: fill .25s, transform .5s $ease-in-out-expo;
131+
margin: 0 0 0 -3px;
132+
content: "";
133+
border-color: currentColor;
134+
border-style: solid;
135+
border-width: 0 2px 2px 0;
136+
transition: transform .3s ease-in-out;
137+
transform: translateY(-50%) rotate(45deg);
133138
}
134139
}
135140

@@ -291,14 +296,8 @@
291296
&__sub-menu-toggle {
292297
top: 8px;
293298
right: 0;
294-
width: 7px;
295-
height: 4px;
296-
297-
.icon {
298-
width: 100%;
299-
height: 100%;
300-
margin: -2px 0 0 -3px;
301-
}
299+
width: 6px;
300+
height: 6px;
302301
}
303302

304303
&__sub-menu {

0 commit comments

Comments
 (0)