Fix semantics of expandable sections (explorer, toc).

This adds the appropriate aria attributes for the [disclosure pattern](https://www.w3.org/WAI/ARIA/apg/patterns/disclosure/examples/disclosure-image-description/#javascriptandcsssourcecode) and uses `visibility: hidden` to remove the hidden elements from the focus order without disrupting the animations. Further work is needed on the tree view nodes.
This commit is contained in:
ndrooo 2024-08-08 13:26:30 -04:00
parent 881a6599f7
commit bba56d0742
6 changed files with 31 additions and 3 deletions

View File

@ -91,6 +91,8 @@ export default ((userOpts?: Partial<Options>) => {
data-collapsed={opts.folderDefaultState} data-collapsed={opts.folderDefaultState}
data-savestate={opts.useSavedState} data-savestate={opts.useSavedState}
data-tree={jsonTree} data-tree={jsonTree}
aria-controls="explorer-content"
aria-expanded={opts.folderDefaultState === "open"}
> >
<h2>{opts.title ?? i18n(cfg.locale).components.explorer.title}</h2> <h2>{opts.title ?? i18n(cfg.locale).components.explorer.title}</h2>
<svg <svg

View File

@ -26,7 +26,13 @@ const TableOfContents: QuartzComponent = ({
return ( return (
<div class={classNames(displayClass, "toc")}> <div class={classNames(displayClass, "toc")}>
<button type="button" id="toc" class={fileData.collapseToc ? "collapsed" : ""}> <button
type="button"
id="toc"
class={fileData.collapseToc ? "collapsed" : ""}
aria-controls="toc-content"
aria-expanded={!fileData.collapseToc}
>
<h3>{i18n(cfg.locale).components.tableOfContents.title}</h3> <h3>{i18n(cfg.locale).components.tableOfContents.title}</h3>
<svg <svg
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"

View File

@ -17,6 +17,10 @@ const observer = new IntersectionObserver((entries) => {
function toggleExplorer(this: HTMLElement) { function toggleExplorer(this: HTMLElement) {
this.classList.toggle("collapsed") this.classList.toggle("collapsed")
this.setAttribute(
"aria-expanded",
this.getAttribute("aria-expanded") === "true" ? "false" : "true",
)
const content = this.nextElementSibling as MaybeHTMLElement const content = this.nextElementSibling as MaybeHTMLElement
if (!content) return if (!content) return

View File

@ -16,6 +16,10 @@ const observer = new IntersectionObserver((entries) => {
function toggleToc(this: HTMLElement) { function toggleToc(this: HTMLElement) {
this.classList.toggle("collapsed") this.classList.toggle("collapsed")
this.setAttribute(
"aria-expanded",
this.getAttribute("aria-expanded") === "true" ? "false" : "true",
)
const content = this.nextElementSibling as HTMLElement | undefined const content = this.nextElementSibling as HTMLElement | undefined
if (!content) return if (!content) return
content.classList.toggle("collapsed") content.classList.toggle("collapsed")

View File

@ -45,8 +45,14 @@ button#explorer {
list-style: none; list-style: none;
overflow: hidden; overflow: hidden;
max-height: none; max-height: none;
transition: max-height 0.35s ease; transition: max-height 0.35s ease, visibility 0s linear 0s;
margin-top: 0.5rem; margin-top: 0.5rem;
visibility: visible;
&.collapsed {
transition: max-height 0.35s ease, visibility 0s linear 0.35s;
visibility: hidden;
}
&.collapsed > .overflow::after { &.collapsed > .overflow::after {
opacity: 0; opacity: 0;

View File

@ -29,8 +29,14 @@ button#toc {
list-style: none; list-style: none;
overflow: hidden; overflow: hidden;
max-height: none; max-height: none;
transition: max-height 0.5s ease; transition: max-height 0.5s ease, visibility 0s linear 0s;
position: relative; position: relative;
visibility: visible;
&.collapsed {
transition: max-height 0.5s ease, visibility 0s linear 0.5s;
visibility: hidden;
}
&.collapsed > .overflow::after { &.collapsed > .overflow::after {
opacity: 0; opacity: 0;