From e646b062c8760ba254ef605f17a9e0af26c764bb Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Tue, 30 Jun 2026 11:39:07 +0000 Subject: [PATCH] feat(a11y): add contextual ARIA labels to generic list buttons in citation component Co-authored-by: aicoder2009 <127642633+aicoder2009@users.noreply.github.com> --- .jules/palette.md | 4 ++++ src/components/wiki/sortable-citation.tsx | 15 +++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/.jules/palette.md b/.jules/palette.md index 752c04a..c1924d3 100644 --- a/.jules/palette.md +++ b/.jules/palette.md @@ -5,3 +5,7 @@ ## 2024-05-17 - Generic Visual Text Buttons and ARIA Context **Learning:** Components frequently use generic visual text buttons like `[hide]`, `[show]`, `[edit]`, or `[delete]` within lists or loops. Screen readers read these buttons without surrounding visual context, confusing users. **Action:** Always provide a contextual `aria-label` (e.g., `aria-label="Hide ${title}"`) for generic visual text buttons so screen reader users have proper context. + +## 2024-06-30 - Contextual ARIA labels for generic list buttons +**Learning:** Generic text buttons in repeated lists (like `[edit]`, `[delete]`, `[copy]`) can be confusing for screen reader users when their context isn't explicit, even if they aren't icon-only buttons. Furthermore, dynamically updating buttons (like a `[copy]` button that briefly changes to `[copied!]`) can cause screen readers to announce incorrect information if the `aria-label` doesn't match the new dynamic state. +**Action:** Always provide specific context in `aria-label`s for generic action buttons inside repeated items, and conditionally update the `aria-label` to match the visual dynamic state of the button (e.g., `aria-label={isCopied ? "Copied" : "Copy"}`). diff --git a/src/components/wiki/sortable-citation.tsx b/src/components/wiki/sortable-citation.tsx index da2d6d6..eee66f2 100644 --- a/src/components/wiki/sortable-citation.tsx +++ b/src/components/wiki/sortable-citation.tsx @@ -359,6 +359,7 @@ export function SortableCitation({ setTimeout(() => setCopiedKey(null), 1500); }} className="text-wiki-link text-sm hover:underline focus-visible:outline-dotted focus-visible:outline-1 focus-visible:outline-wiki-text" + aria-label={copiedKey === "copy" ? "Copied citation" : "Copy citation"} > {copiedKey === "copy" ? "[copied!]" : "[copy]"} @@ -376,6 +377,7 @@ export function SortableCitation({ }} className="text-wiki-link text-sm hover:underline focus-visible:outline-dotted focus-visible:outline-1 focus-visible:outline-wiki-text" title={`In-text citation (${citation.style.toUpperCase()})`} + aria-label={copiedKey === "copy-in-text" ? "Copied in-text citation" : "Copy in-text citation"} > {copiedKey === "copy-in-text" ? "[copied!]" : "[copy in-text]"} @@ -383,6 +385,7 @@ export function SortableCitation({ @@ -390,6 +393,7 @@ export function SortableCitation({ @@ -397,6 +401,7 @@ export function SortableCitation({ @@ -446,6 +451,7 @@ export function SortableCitation({ setEditingNotes(true); }} className="text-wiki-link text-xs hover:underline focus-visible:outline-dotted focus-visible:outline-1 focus-visible:outline-wiki-text" + aria-label="Edit notes" > [edit] @@ -469,6 +475,7 @@ export function SortableCitation({ setEditingNotes(true); }} className="text-wiki-link text-xs hover:underline focus-visible:outline-dotted focus-visible:outline-1 focus-visible:outline-wiki-text" + aria-label="Add notes to citation" > [+ add notes] @@ -515,6 +522,7 @@ export function SortableCitation({ setQuotesDraft(quotesDraft.filter((_, idx) => idx !== i)) } className="text-wiki-link text-xs hover:underline pt-1 focus-visible:outline-dotted focus-visible:outline-1 focus-visible:outline-wiki-text" + aria-label={`Remove quote ${i + 1}`} > [remove] @@ -526,6 +534,7 @@ export function SortableCitation({ setQuotesDraft([...quotesDraft, { text: "", page: "" }]) } className="text-wiki-link text-xs hover:underline focus-visible:outline-dotted focus-visible:outline-1 focus-visible:outline-wiki-text" + aria-label="Add another quote" > + add quote @@ -563,6 +572,7 @@ export function SortableCitation({ setEditingQuotes(true); }} className="text-wiki-link text-xs hover:underline focus-visible:outline-dotted focus-visible:outline-1 focus-visible:outline-wiki-text" + aria-label="Edit quotes" > [edit] @@ -587,6 +597,7 @@ export function SortableCitation({ setEditingQuotes(true); }} className="text-wiki-link text-xs hover:underline focus-visible:outline-dotted focus-visible:outline-1 focus-visible:outline-wiki-text" + aria-label="Add quotes to citation" > [+ add quote] @@ -637,6 +648,7 @@ export function SortableCitation({ @@ -646,6 +658,7 @@ export function SortableCitation({ setNewTagInput(""); }} className="text-wiki-text-muted text-xs hover:underline focus-visible:outline-dotted focus-visible:outline-1 focus-visible:outline-wiki-text" + aria-label="Cancel adding tag" > [cancel] @@ -669,6 +682,7 @@ export function SortableCitation({ onClick={() => onAddTag(citation.id, tag)} className={`inline-flex items-center px-2 py-0.5 text-xs border focus-visible:outline-dotted focus-visible:outline-1 focus-visible:outline-wiki-text ${color.bg} ${color.text} ${color.border}`} title={`Add "${tag}"`} + aria-label={`Add tag ${tag}`} > + {tag} @@ -682,6 +696,7 @@ export function SortableCitation({