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 @@
## 2025-04-29 - Missing ID Mapping in Interactive Widgets
**Learning:** Custom interactive widgets (like collapsibles and tabs) across the codebase often miss `aria-controls` mapping because generating unique IDs manually is cumbersome.
**Action:** Use React's `useId` hook consistently in these components to generate unique IDs and map `aria-controls` to the content containers and `aria-expanded` attributes on toggle buttons, improving screen reader context.
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