Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .jules/palette.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
## 2026-05-01 - Add context to interactive widgets lacking descriptive labels
**Learning:** Generic visual labels like `[hide]` or `[show]` on interactive widgets lack context for screen reader users when they navigate out of the visual flow. Relying purely on visual layout for context is a common accessibility trap.
**Action:** Always provide a contextual `aria-label` (e.g., `"Hide [Section Title]"`) when the visual text of a button is ambiguous or repetitive. Additionally, use `useId` to reliably map `aria-controls` to the content `id` avoiding collisions.
8 changes: 6 additions & 2 deletions src/components/wiki/wiki-collapsible.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"use client";

import { useState } from "react";
import { useState, useId } from "react";

interface WikiCollapsibleProps {
title: string;
Expand All @@ -14,6 +14,7 @@ export function WikiCollapsible({
defaultOpen = true,
}: WikiCollapsibleProps) {
const [isOpen, setIsOpen] = useState(defaultOpen);
const contentId = useId();

return (
<div className="border border-wiki-border-light bg-wiki-offwhite">
Expand All @@ -22,11 +23,14 @@ export function WikiCollapsible({
<button
onClick={() => setIsOpen(!isOpen)}
className="text-wiki-link text-sm hover:underline"
aria-expanded={isOpen}
aria-controls={contentId}
aria-label={`${isOpen ? "Hide" : "Show"} ${title}`}
>
[{isOpen ? "hide" : "show"}]
</button>
</div>
{isOpen && <div className="px-4 py-3">{children}</div>}
{isOpen && <div id={contentId} className="px-4 py-3">{children}</div>}
</div>
);
}
Loading