Make the "Other" dropdown accessible

Expose its state with aria-expanded, close it on outside clicks,
Escape and when focus leaves, restore the focus outline, and move the
inline margins into CSS.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
leanderandClaude Opus 5.5 committed 2026-10-30 22:53:03 +01:00
1 parent eab0e0bbab
commit 633237f262
2 files changed
+61 -13

No files matched your search

+6 -5
View File
@@ -39,13 +39,10 @@
.dropdownLink {
display: block;
width: 100%;
margin-top: 4px;
color: black;
background-color: #cccccc;
border: none;
border-radius: 999em !important;
cursor: pointer;
outline: none;
border-radius: 10px;
border-radius: 999em;
text-align: left;
font-size: 1.6rem;
box-shadow: var(--shadow);
@@ -53,6 +50,10 @@
padding-right: 2em;
}
.dropdownLink:first-child {
margin-top: 8px;
}
.dropdownLink:hover {
color: black;
background-color: #e6e6e6;
+55 -8
View File
@@ -1,6 +1,6 @@
"use client"
import { useState } from "react"
import { useEffect, useId, useRef, useState } from "react"
import { useLocale, useTranslations } from "next-intl"
import * as styles from "./otherButton.module.css"
@@ -11,7 +11,37 @@ const OtherButton = () => {
const locale = useLocale()
const [isOpen, setIsOpen] = useState(false)
const toggleDropdown = () => setIsOpen(!isOpen)
const toggleDropdown = () => setIsOpen(open => !open)
const containerRef = useRef<HTMLDivElement>(null)
const buttonRef = useRef<HTMLButtonElement>(null)
const dropdownId = useId()
// Close when clicking outside the dropdown or pressing Escape
useEffect(() => {
if (!isOpen) return
const handlePointerDown = (event: PointerEvent) => {
if (!containerRef.current?.contains(event.target as Node)) {
setIsOpen(false)
}
}
const handleKeyDown = (event: KeyboardEvent) => {
if (event.key === "Escape") {
setIsOpen(false)
buttonRef.current?.focus()
}
}
document.addEventListener("pointerdown", handlePointerDown)
document.addEventListener("keydown", handleKeyDown)
return () => {
document.removeEventListener("pointerdown", handlePointerDown)
document.removeEventListener("keydown", handleKeyDown)
}
}, [isOpen])
const statutesUrl =
locale === "en"
@@ -28,21 +58,38 @@ const OtherButton = () => {
]
return (
<div className={styles.dropdownContainer}>
<button onClick={toggleDropdown} className={styles.button}>
<div
ref={containerRef}
className={styles.dropdownContainer}
// Close when keyboard focus moves out of the dropdown
onBlur={event => {
if (!event.currentTarget.contains(event.relatedTarget)) {
setIsOpen(false)
}
}}
>
<button
ref={buttonRef}
onClick={toggleDropdown}
className={styles.button}
aria-expanded={isOpen}
aria-controls={dropdownId}
>
{t("other")}{" "}
<span className={isOpen ? styles.arrowUp : styles.arrowDown}></span>
<span
className={isOpen ? styles.arrowUp : styles.arrowDown}
aria-hidden="true"
></span>
</button>
{isOpen && (
<div className={styles.dropdown}>
{links.map((link, index) => (
<div id={dropdownId} className={styles.dropdown}>
{links.map(link => (
<a
key={link.url}
href={link.url}
target="_blank"
rel="noopener noreferrer"
className={styles.dropdownLink}
style={{ marginTop: index === 0 ? "8px" : "4px" }}
>
{link.label}
</a>