Skip to content
Merged
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
4 changes: 4 additions & 0 deletions .jules/palette.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,10 @@
**Learning:** Found multiple interactive `<button>` elements in user-facing components (`UserManagementPanel`, `UserMenuWidget`) that lacked keyboard focus indicators. This makes navigation via keyboard difficult for users relying on alternative inputs.
**Action:** When creating or maintaining new buttons, always append `focus-visible:ring-1 focus-visible:ring-[color] outline-none` to ensure standard keyboard accessibility across the UI.

## 2026-05-17 - Accessible Disabled Buttons
**Learning:** Using the native HTML `disabled` attribute on buttons (e.g. 'Add to Watchlist') often causes them to be removed from the tab order and swallow pointer events in certain browsers. This prevents keyboard users from focusing them and prevents visual users from seeing dynamic tooltips explaining *why* the button is disabled.
**Action:** For complex UI actions where the user needs to know why an action is unavailable, use `aria-disabled="true"` combined with visual styling (e.g. Tailwind's `aria-disabled:opacity-30`) and ensure dynamic `title` and `aria-label` attributes explain the missing requirements.

## 2026-05-20 - Ensure Accordion Components Include ARIA Attributes
**Learning:** Found an accordion header (`CollapsibleSection` in `ListeningPost.tsx`) lacking the `aria-expanded` state attribute and `aria-controls` link to its expandable content. Without these, screen reader users cannot tell whether the section is open or closed, nor programmatically follow the link to the content.
**Action:** When creating or modifying collapsible widgets, always ensure the toggle button receives `aria-expanded={isOpen}` and `aria-controls={contentId}`, with the expanded content container holding the matching `id={contentId}`.
Expand Down
11 changes: 7 additions & 4 deletions frontend/src/components/widgets/WatchlistManager.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,13 @@ export const WatchlistManager: React.FC<WatchlistManagerProps> = ({
className="flex-1 bg-black/50 border border-white/10 rounded px-2 py-1 text-[10px] font-mono text-white placeholder-white/20 focus:outline-none focus:border-hud-green/50 focus:ring-1 focus:ring-hud-green/50 uppercase"
/>
<button
onClick={addEntry}
disabled={newIcao24.length !== 6 || addLoading}
className="flex items-center gap-1 px-2.5 py-1 rounded bg-hud-green/10 border border-hud-green/30 text-hud-green hover:bg-hud-green/20 disabled:opacity-30 disabled:hover:bg-hud-green/10 transition-colors focus-visible:ring-1 focus-visible:ring-hud-green outline-none"
title="Add to watchlist (permanent)"
onClick={() => {
if (newIcao24.length === 6 && !addLoading) addEntry();
}}
aria-disabled={newIcao24.length !== 6 || addLoading}
className="flex items-center gap-1 px-2.5 py-1 rounded bg-hud-green/10 border border-hud-green/30 text-hud-green hover:bg-hud-green/20 aria-disabled:opacity-30 aria-disabled:hover:bg-hud-green/10 aria-disabled:cursor-not-allowed transition-colors focus-visible:ring-1 focus-visible:ring-hud-green outline-none"
title={addLoading ? "Adding to watchlist..." : newIcao24.length !== 6 ? "Requires 6-character hex code" : "Add to watchlist (permanent)"}
aria-label={addLoading ? "Adding to watchlist" : newIcao24.length !== 6 ? "Requires 6-character hex code to add" : "Add to watchlist"}
>
{addLoading ? (
<Loader2 size={11} className="animate-spin" />
Expand Down