Improved accessibility of sidebar navigation

This commit is contained in:
squidfunk 2023-01-28 12:54:19 +01:00
parent ad6c47ddb6
commit 148c9fdba4
8 changed files with 46 additions and 30 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -240,7 +240,7 @@
</script> </script>
{% endblock %} {% endblock %}
{% block scripts %} {% block scripts %}
<script src="{{ 'assets/javascripts/bundle.51d95adb.min.js' | url }}"></script> <script src="{{ 'assets/javascripts/bundle.a6ba2619.min.js' | url }}"></script>
{% for path in config.extra_javascript %} {% for path in config.extra_javascript %}
<script src="{{ path | url }}"></script> <script src="{{ path | url }}"></script>
{% endfor %} {% endfor %}

View File

@ -19,7 +19,7 @@
{% if expanded and not checked %} {% if expanded and not checked %}
{% set indeterminate = "md-toggle--indeterminate" %} {% set indeterminate = "md-toggle--indeterminate" %}
{% endif %} {% endif %}
<input class="md-nav__toggle md-toggle {{ indeterminate }}" data-md-toggle="{{ path }}" type="checkbox" id="{{ path }}" {{ checked }}> <input class="md-nav__toggle md-toggle {{ indeterminate }}" type="checkbox" id="{{ path }}" {{ checked }}>
{% set indexes = [] %} {% set indexes = [] %}
{% if "navigation.indexes" in features %} {% if "navigation.indexes" in features %}
{% for nav_item in nav_item.children %} {% for nav_item in nav_item.children %}
@ -29,7 +29,7 @@
{% endfor %} {% endfor %}
{% endif %} {% endif %}
{% if not indexes %} {% if not indexes %}
<label class="md-nav__link" for="{{ path }}" tabindex="0" aria-expanded="{{ nav_item.active | tojson }}"> <label class="md-nav__link" for="{{ path }}" id="{{ path }}_label" tabindex="0">
{{ nav_item.title }} {{ nav_item.title }}
<span class="md-nav__icon md-icon"></span> <span class="md-nav__icon md-icon"></span>
</label> </label>
@ -45,7 +45,7 @@
{% endif %} {% endif %}
</div> </div>
{% endif %} {% endif %}
<nav class="md-nav" aria-label="{{ nav_item.title }}" data-md-level="{{ level }}"> <nav class="md-nav" data-md-level="{{ level }}" aria-labelledby="{{ path }}_label" aria-expanded="{{ nav_item.active | tojson }}">
<label class="md-nav__title" for="{{ path }}"> <label class="md-nav__title" for="{{ path }}">
<span class="md-nav__icon md-icon"></span> <span class="md-nav__icon md-icon"></span>
{{ nav_item.title }} {{ nav_item.title }}
@ -62,7 +62,7 @@
{% elif nav_item == page %} {% elif nav_item == page %}
<li class="{{ class }}"> <li class="{{ class }}">
{% set toc = page.toc %} {% set toc = page.toc %}
<input class="md-nav__toggle md-toggle" data-md-toggle="toc" type="checkbox" id="__toc"> <input class="md-nav__toggle md-toggle" type="checkbox" id="__toc">
{% set first = toc | first %} {% set first = toc | first %}
{% if first and first.level == 1 %} {% if first and first.level == 1 %}
{% set toc = first.children %} {% set toc = first.children %}

View File

@ -192,14 +192,8 @@ keyboard$
/* Expand navigation, see https://bit.ly/3ZjG5io */ /* Expand navigation, see https://bit.ly/3ZjG5io */
case "Enter": case "Enter":
const active = getActiveElement() const active = getActiveElement()
if (active instanceof HTMLLabelElement) { if (active instanceof HTMLLabelElement)
const id = `[id="${active.htmlFor}"]` active.click()
const input = getElement<HTMLInputElement>(id)
active.setAttribute(
"aria-expanded",
`${input.checked = !input.checked}`
)
}
} }
}) })

View File

@ -28,9 +28,15 @@ import {
combineLatest, combineLatest,
defer, defer,
distinctUntilChanged, distinctUntilChanged,
endWith,
finalize, finalize,
first, first,
from,
fromEvent,
ignoreElements,
map, map,
mergeMap,
takeUntil,
tap, tap,
withLatestFrom withLatestFrom
} from "rxjs" } from "rxjs"
@ -153,6 +159,7 @@ export function mountSidebar(
const { y } = getElementOffset(inner) const { y } = getElementOffset(inner)
return defer(() => { return defer(() => {
const push$ = new Subject<Sidebar>() const push$ = new Subject<Sidebar>()
const done$ = push$.pipe(ignoreElements(), endWith(true))
const next$ = push$ const next$ = push$
.pipe( .pipe(
auditTime(0, animationFrameScheduler) auditTime(0, animationFrameScheduler)
@ -190,6 +197,22 @@ export function mountSidebar(
} }
}) })
/* Handle accessibility for expandable items, see https://bit.ly/3jaod9p */
from(getElements<HTMLLabelElement>("label[tabindex]", el))
.pipe(
mergeMap(label => fromEvent(label, "click")
.pipe(
map(() => label),
takeUntil(done$)
)
)
)
.subscribe(label => {
const input = getElement<HTMLInputElement>(`[id="${label.htmlFor}"]`)
const nav = getElement(`[aria-labelledby="${label.id}"]`)
nav.setAttribute("aria-expanded", `${input.checked}`)
})
/* Create and return component */ /* Create and return component */
return watchSidebar(el, options) return watchSidebar(el, options)
.pipe( .pipe(

View File

@ -53,7 +53,6 @@
<!-- Active checkbox expands items contained within nested section --> <!-- Active checkbox expands items contained within nested section -->
<input <input
class="md-nav__toggle md-toggle {{ indeterminate }}" class="md-nav__toggle md-toggle {{ indeterminate }}"
data-md-toggle="{{ path }}"
type="checkbox" type="checkbox"
id="{{ path }}" id="{{ path }}"
{{ checked }} {{ checked }}
@ -74,8 +73,8 @@
<label <label
class="md-nav__link" class="md-nav__link"
for="{{ path }}" for="{{ path }}"
id="{{ path }}_label"
tabindex="0" tabindex="0"
aria-expanded="{{ nav_item.active | tojson }}"
> >
{{ nav_item.title }} {{ nav_item.title }}
<span class="md-nav__icon md-icon"></span> <span class="md-nav__icon md-icon"></span>
@ -100,8 +99,9 @@
<!-- Render nested navigation --> <!-- Render nested navigation -->
<nav <nav
class="md-nav" class="md-nav"
aria-label="{{ nav_item.title }}"
data-md-level="{{ level }}" data-md-level="{{ level }}"
aria-labelledby="{{ path }}_label"
aria-expanded="{{ nav_item.active | tojson }}"
> >
<label class="md-nav__title" for="{{ path }}"> <label class="md-nav__title" for="{{ path }}">
<span class="md-nav__icon md-icon"></span> <span class="md-nav__icon md-icon"></span>
@ -127,7 +127,6 @@
<!-- Active checkbox expands items contained within nested section --> <!-- Active checkbox expands items contained within nested section -->
<input <input
class="md-nav__toggle md-toggle" class="md-nav__toggle md-toggle"
data-md-toggle="toc"
type="checkbox" type="checkbox"
id="__toc" id="__toc"
/> />