Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
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-24 - Dynamic ARIA Labels in Lists
**Learning:** When adding ARIA labels to repeating elements in a list (like delete/confirmation buttons in a sidebar chat list), injecting dynamic context (e.g., `conv.title`) is essential for screen reader users to distinguish which item they are acting upon, rather than hearing repeating identical labels.
**Action:** Always look for and utilize existing dynamic data (like titles or IDs) within mapping functions to create unique, descriptive ARIA labels for list item actions.
3 changes: 3 additions & 0 deletions apps/app/src/components/ConversationsSidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,7 @@ export function ConversationsSidebar({
className="px-1.5 py-0.5 text-[10px] border border-danger bg-danger text-white cursor-pointer hover:opacity-90 disabled:opacity-50 disabled:cursor-not-allowed"
onClick={() => void handleConfirmDelete(conv.id)}
disabled={deletingId === conv.id}
aria-label={`Confirm delete conversation: ${conv.title}`}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The aria-label for the confirmation button should reflect the current state of the deletion process. When deletingId === conv.id, the button text changes to "...", but the label remains "Confirm delete...". Updating the label to indicate that deletion is in progress provides better context for screen reader users.

Suggested change
aria-label={`Confirm delete conversation: ${conv.title}`}
aria-label={(deletingId === conv.id ? "Deleting" : "Confirm delete") + " conversation: " + conv.title}

>
{deletingId === conv.id ? "..." : "Yes"}
</button>
Comment on lines 199 to 205

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The async handler handleConfirmDelete is invoked with void handleConfirmDelete(conv.id), but any errors thrown during deletion are silently ignored. This can lead to a poor user experience if the deletion fails, as the user receives no feedback and the UI may become inconsistent.

Recommendation:
Consider adding error handling and user feedback for failed deletions. For example, you could display a toast or inline error message if the deletion fails:

try {
  await handleConfirmDelete(conv.id);
} catch (err) {
  // Show error to user
}

Alternatively, handle errors inside handleConfirmDelete and provide feedback accordingly.

Expand All @@ -207,6 +208,7 @@ export function ConversationsSidebar({
className="px-1.5 py-0.5 text-[10px] border border-border bg-card text-muted cursor-pointer hover:border-accent hover:text-accent disabled:opacity-50 disabled:cursor-not-allowed"
onClick={() => setConfirmDeleteId(null)}
disabled={deletingId === conv.id}
aria-label={`Cancel delete conversation: ${conv.title}`}
>
No
</button>
Expand All @@ -221,6 +223,7 @@ export function ConversationsSidebar({
setConfirmDeleteId(conv.id);
}}
title="Delete conversation"
aria-label={`Delete conversation: ${conv.title}`}
>
×
</button>
Expand Down
Loading