Skip to content

Commit fe71ebe

Browse files
authored
fix: accesibility improvements (#1118)
* fix: accesibility improvements * fix: accesitility improvements and focus handlers
1 parent 3d48937 commit fe71ebe

File tree

3 files changed

+173
-28
lines changed

3 files changed

+173
-28
lines changed

src/components/PbNavbar.vue

Lines changed: 171 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
>
1010
<div class="max-w-screen-xl flex flex-wrap items-center justify-between mx-auto py-[30px]">
1111
<a
12+
id="logo"
1213
href="https://pressbooks.com/"
1314
title="Pressbooks Home Page"
1415
data-cy="return-home-button"
@@ -48,10 +49,22 @@
4849
class="hidden w-full lg:block lg:w-auto"
4950
>
5051
<ul class="font-medium flex items-start lg:items-center gap-4 flex-col p-4 lg:p-0 mt-4 border border-gray-100 rounded-lg bg-gray-50 lg:flex-row lg:mt-0 lg:border-0 lg:bg-white">
51-
<li class="group relative">
52+
<li
53+
class="group relative"
54+
role="menuitem"
55+
@mouseleave="hideSubmenu('products')"
56+
>
5257
<a
5358
href="#"
59+
aria-haspopup="true"
60+
aria-expanded="false"
5461
class="flex gap-0.5 items-center py-2 pl-3 pr-4 text-pb-dark-blue rounded hover:bg-gray-100 lg:hover:bg-transparent lg:border-0 lg:hover:text-pb-red lg:p-0 font-semibold text-[18px]"
62+
@keydown.enter.prevent="toggleSubmenu('products')"
63+
@keydown.space.prevent="toggleSubmenu('products')"
64+
@focus="showSubmenu('products')"
65+
@mouseover="!isTouchDevice.value && showSubmenu('products')"
66+
@keydown.shift.tab.prevent="closeAndFocusPrev('products')"
67+
@click.prevent="isTouchDevice.value && toggleSubmenu('products')"
5568
>
5669
Products
5770
<span class="ml-1">
@@ -70,32 +83,50 @@
7083
</svg>
7184
</span>
7285
</a>
73-
<!-- Dropdown menu -->
74-
<ul class="absolute hidden group-hover:block bg-white shadow-lg -mt-1 rounded-lg p-4 space-y-2 z-50 min-w-60">
75-
<li>
86+
<ul
87+
v-show="isSubmenuVisible('products')"
88+
id="products"
89+
ref="products"
90+
class="absolute bg-white shadow-lg -mt-1 rounded-lg p-4 space-y-2 z-50 min-w-60"
91+
role="menu"
92+
>
93+
<li role="menuitem">
7694
<a
7795
href="https://pressbooks.com/enterprise/"
7896
class="text-gray-500 font-semibold text-[18px]"
97+
@keydown.shift.tab.prevent="focusParent('products')"
7998
>Enterprise</a>
8099
</li>
81-
<li>
100+
<li role="menuitem">
82101
<a
83102
href="https://pressbooks.com/self-publisher/"
84103
class="text-gray-500 font-semibold text-[18px]"
85104
>Self-Publisher</a>
86105
</li>
87-
<li>
106+
<li role="menuitem">
88107
<a
89108
href="/"
90109
class="text-gray-500 font-semibold text-[18px]"
110+
@blur="hideSubmenu('products')"
91111
>Pressbooks Directory</a>
92112
</li>
93113
</ul>
94114
</li>
95-
<li class="group relative">
115+
<li
116+
class="group relative"
117+
@mouseleave="hideSubmenu('plans')"
118+
>
96119
<a
97-
href="https://pressbooks.com/plans-pricing/"
120+
aria-haspopup="true"
121+
aria-expanded="false"
122+
href="#"
98123
class="flex gap-0.5 items-center py-2 pl-3 pr-4 text-pb-dark-blue rounded hover:bg-gray-100 lg:hover:bg-transparent lg:border-0 lg:hover:text-pb-red lg:p-0 font-semibold text-[18px]"
124+
@keydown.enter.prevent="toggleSubmenu('plans')"
125+
@keydown.space.prevent="toggleSubmenu('plans')"
126+
@focus="showSubmenu('plans')"
127+
@mouseover="!isTouchDevice.value && showSubmenu('plans')"
128+
@keydown.shift.tab.prevent="closeAndFocusPrev('plans')"
129+
@click.prevent="isTouchDevice.value && toggleSubmenu('plans')"
99130
>
100131
Plans & Pricing
101132
<span class="ml-1">
@@ -114,25 +145,44 @@
114145
</svg>
115146
</span>
116147
</a>
117-
<ul class="absolute hidden group-hover:block bg-white shadow-lg -mt-1 rounded-lg p-4 space-y-2 z-50 min-w-60">
118-
<li>
148+
<ul
149+
v-show="isSubmenuVisible('plans')"
150+
id="plans"
151+
ref="plans"
152+
class="absolute group-hover:block bg-white shadow-lg -mt-1 rounded-lg p-4 space-y-2 z-50 min-w-60"
153+
role="menu"
154+
>
155+
<li role="menuitem">
119156
<a
120157
href="https://pressbooks.com/educational-institutions-plans-and-pricing/"
121158
class="text-gray-500 font-semibold text-[18px]"
159+
@keydown.shift.tab.prevent="focusParent('plans')"
122160
>Enterprise Networks</a>
123161
</li>
124-
<li>
162+
<li role="menuitem">
125163
<a
126164
href="https://pressbooks.com/self-publisher-plans-and-pricing/"
127165
class="text-gray-500 font-semibold text-[18px]"
166+
@blur="hideSubmenu('plans')"
128167
>Self-Publisher Plans</a>
129168
</li>
130169
</ul>
131170
</li>
132-
<li class="group relative">
171+
<li
172+
class="group relative"
173+
@mouseleave="hideSubmenu('resources')"
174+
>
133175
<a
176+
aria-haspopup="true"
177+
aria-expanded="false"
134178
href="#"
135179
class="flex gap-0.5 items-center py-2 pl-3 pr-4 text-pb-dark-blue rounded hover:bg-gray-100 lg:hover:bg-transparent lg:border-0 lg:hover:text-pb-red lg:p-0 font-semibold text-[18px]"
180+
@keydown.enter.prevent="toggleSubmenu('resources')"
181+
@keydown.space.prevent="toggleSubmenu('resources')"
182+
@focus="showSubmenu('resources')"
183+
@mouseover="!isTouchDevice.value && showSubmenu('resources')"
184+
@keydown.shift.tab.prevent="closeAndFocusPrev('resources')"
185+
@click.prevent="isTouchDevice.value && toggleSubmenu('resources')"
136186
>
137187
Resources
138188
<span class="ml-1">
@@ -151,49 +201,68 @@
151201
</svg>
152202
</span>
153203
</a>
154-
<ul class="absolute hidden group-hover:block bg-white shadow-lg -mt-1 rounded-lg p-4 space-y-2 z-50 min-w-60">
155-
<li>
204+
<ul
205+
v-show="isSubmenuVisible('resources')"
206+
id="resources"
207+
ref="resources"
208+
class="absolute group-hover:block bg-white shadow-lg -mt-1 rounded-lg p-4 space-y-2 z-50 min-w-60"
209+
role="menu"
210+
>
211+
<li role="menuitem">
156212
<a
157213
href="https://pressbooks.com/collections-hub/"
158214
class="text-gray-500 font-semibold text-[18px]"
215+
@keydown.shift.tab.prevent="focusParent('resources')"
159216
>Collections Hub</a>
160217
</li>
161-
<li>
218+
<li role="menuitem">
162219
<a
163220
href="https://pressbooks.com/category/success-stories/"
164221
class="text-gray-500 font-semibold text-[18px]"
165222
>Success Stories</a>
166223
</li>
167-
<li>
224+
<li role="menuitem">
168225
<a
169226
href="https://pressbooks.com/pressbooks-blog/"
170227
class="text-gray-500 font-semibold text-[18px]"
171228
>Blog</a>
172229
</li>
173-
<li>
230+
<li role="menuitem">
174231
<a
175232
href="/"
176233
class="text-gray-500 font-semibold text-[18px]"
177234
>Pressbooks Directory</a>
178235
</li>
179-
<li>
236+
<li role="menuitem">
180237
<a
181238
href="https://pressbooks.com/support/"
182239
class="text-gray-500 font-semibold text-[18px]"
183240
>Support Guides</a>
184241
</li>
185-
<li>
242+
<li role="menuitem">
186243
<a
187244
href="https://pressbooks.com/webinars/"
188245
class="text-gray-500 font-semibold text-[18px]"
246+
@blur="hideSubmenu('resources')"
189247
>Events & Webinars</a>
190248
</li>
191249
</ul>
192250
</li>
193-
<li class="group relative">
251+
<li
252+
class="group relative"
253+
@mouseleave="hideSubmenu('about')"
254+
>
194255
<a
195-
href="https://pressbooks.com/about/"
256+
aria-haspopup="true"
257+
aria-expanded="false"
258+
href="#"
196259
class="flex gap-0.5 items-center py-2 pl-3 pr-4 text-pb-dark-blue rounded hover:bg-gray-100 lg:hover:bg-transparent lg:border-0 lg:hover:text-pb-red lg:p-0 font-semibold text-[18px]"
260+
@keydown.enter.prevent="toggleSubmenu('about')"
261+
@keydown.space.prevent="toggleSubmenu('about')"
262+
@focus="showSubmenu('about')"
263+
@mouseover="!isTouchDevice.value && showSubmenu('about')"
264+
@keydown.shift.tab.prevent="closeAndFocusPrev('about')"
265+
@click.prevent="isTouchDevice.value && toggleSubmenu('about')"
197266
>
198267
About
199268
<span class="ml-1">
@@ -212,27 +281,36 @@
212281
</svg>
213282
</span>
214283
</a>
215-
<ul class="absolute hidden group-hover:block bg-white shadow-lg -mt-1 rounded-lg p-4 space-y-2 z-50 min-w-60">
216-
<li>
284+
<ul
285+
v-show="isSubmenuVisible('about')"
286+
id="about"
287+
ref="about"
288+
class="absolute group-hover:block bg-white shadow-lg -mt-1 rounded-lg p-4 space-y-2 z-50 min-w-60"
289+
role="menu"
290+
>
291+
<li role="menuitem">
217292
<a
218293
href="https://pressbooks.com/about/"
219294
class="text-gray-500 font-semibold text-[18px]"
295+
@keydown.shift.tab.prevent="focusParent('about')"
220296
>About Pressbooks</a>
221297
</li>
222-
<li>
298+
<li role="menuitem">
223299
<a
224300
href="https://pressbooks.com/pressbooks-team/"
225301
class="text-gray-500 font-semibold text-[18px]"
226302
>Our Team</a>
227303
</li>
228-
<li>
304+
<li role="menuitem">
229305
<a
230306
href="https://pressbooks.com/category/inside-pressbooks/"
231307
class="text-gray-500 font-semibold text-[18px]"
308+
@blur="hideSubmenu('about')"
232309
>Inside Pressbooks</a>
233310
</li>
234311
</ul>
235312
</li>
313+
<!-- Request a Demo Button -->
236314
<li class="lg:inline-block lg:text-center lg:border-2 lg:border-red-700 lg:text-white lg:bg-red-700 lg:rounded-full lg:leading-[20px] lg:ml-24">
237315
<a
238316
href="https://pressbooks.com/request-a-pressbooks-demo/"
@@ -246,7 +324,74 @@
246324
</header>
247325
</template>
248326

249-
<script>
327+
<script setup>
328+
import {ref, onMounted, onUnmounted} from 'vue';
329+
330+
const isTouchDevice = ref(false);
331+
332+
onMounted(() => {
333+
isTouchDevice.value = 'ontouchstart' in window || navigator.maxTouchPoints > 0;
334+
window.addEventListener('keydown', handleKeydown);
335+
});
336+
337+
onUnmounted(() => {
338+
window.removeEventListener('keydown', handleKeydown);
339+
});
340+
341+
const submenus = ref({
342+
products: false,
343+
plans: false,
344+
resources: false,
345+
about: false
346+
});
347+
348+
const closeAllSubmenus = () => {
349+
Object.keys(submenus.value).forEach((key) => {
350+
submenus.value[key] = false;
351+
});
352+
};
353+
354+
const handleKeydown = (event) => {
355+
if (event.key === 'Escape') {
356+
closeAllSubmenus();
357+
}
358+
};
359+
360+
const isSubmenuVisible = (id) => {
361+
return submenus.value[id];
362+
};
363+
364+
const showSubmenu = (id) => {
365+
submenus.value[id] = true;
366+
};
367+
368+
const hideSubmenu = (id) => {
369+
submenus.value[id] = false;
370+
};
371+
372+
const toggleSubmenu = (id) => {
373+
submenus.value[id] = !submenus.value[id];
374+
};
375+
376+
const focusParent = (id) => {
377+
const parentMenu = document.querySelector(`#${id}`).previousElementSibling;
378+
if (parentMenu) {
379+
parentMenu.focus();
380+
}
381+
hideSubmenu(id);
382+
};
383+
384+
const closeAndFocusPrev = (id) => {
385+
if (id === 'products') {
386+
document.getElementById('logo').focus();
387+
}
388+
hideSubmenu(id);
389+
const prevMenu = document.querySelector(`#${id}`).closest('li').previousElementSibling?.querySelector('a');
390+
if (prevMenu) {
391+
prevMenu.focus();
392+
}
393+
};
394+
250395
import {Collapse} from 'flowbite';
251396
252397
const $targetEl = document.getElementById('navbar-top');

src/components/filters/PbSelectableFilters.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,9 @@
2424
class="w-full border-0 text-sm py-2 px-3 focus:outline-none focus:ring-0"
2525
:placeholder="`Search ${title}`"
2626
autocomplete="off"
27-
autocorrect="off"
2827
autocapitalize="none"
2928
spellcheck="false"
29+
aria-label="`Search ${title}`"
3030
>
3131
</div>
3232
<ul

src/components/forms/PbSearchBox.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@
1818
placeholder="Find a book"
1919
data-cy="book-input-search"
2020
autocomplete="off"
21-
autocorrect="off"
2221
autocapitalize="none"
2322
spellcheck="false"
23+
aria-label="Search a book"
2424
>
2525
</div>
2626
</div>

0 commit comments

Comments
 (0)