Skip to content
Open
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 @@
## 2024-03-20 - Icon-Only Button ARIA Labels
**Learning:** Found a recurring pattern in `VideoGrid` where icon-only control buttons for Mic, Cam, and Screen Share lacked proper `aria-label` attributes, making them inaccessible to screen readers. They also had dynamic states (on/off) which should be reflected in the label.
**Action:** Always ensure that any button containing only an icon component (like those from `lucide-react`) has a descriptive, dynamic `aria-label` that reflects its current state and action.
9 changes: 6 additions & 3 deletions src/components/room/video-grid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -85,13 +85,13 @@ export function VideoGrid({
{/* In-Card Controls - Mobile Only (Bottom Bar handles Desktop) */}
<div className="md:hidden absolute bottom-3 left-0 right-0 flex justify-center items-center z-20">
<div className="flex gap-3 p-2 bg-black/60 backdrop-blur-md rounded-full border border-white/10 shadow-xl">
<button onClick={(e) => { e.stopPropagation(); toggleMic(); }} className={cn("p-2 rounded-full transition-all active:scale-95", isMicOn ? "bg-emerald-500 text-white" : "bg-red-500 text-white")}>
<button onClick={(e) => { e.stopPropagation(); toggleMic(); }} aria-label={isMicOn ? "Mute Microphone" : "Unmute Microphone"} className={cn("p-2 rounded-full transition-all active:scale-95", isMicOn ? "bg-emerald-500 text-white" : "bg-red-500 text-white")}>
{isMicOn ? <Mic className="w-5 h-5" /> : <MicOff className="w-5 h-5" />}
</button>
<button onClick={(e) => { e.stopPropagation(); toggleCam(); }} className={cn("p-2 rounded-full transition-all active:scale-95", isCamOn ? "bg-white/10 text-white" : "bg-red-500 text-white")}>
<button onClick={(e) => { e.stopPropagation(); toggleCam(); }} aria-label={isCamOn ? "Turn Camera Off" : "Turn Camera On"} className={cn("p-2 rounded-full transition-all active:scale-95", isCamOn ? "bg-white/10 text-white" : "bg-red-500 text-white")}>
{isCamOn ? <Video className="w-5 h-5" /> : <VideoOff className="w-5 h-5" />}
</button>
<button onClick={(e) => { e.stopPropagation(); toggleScreen(); }} className="p-2 rounded-full bg-white/10 text-white transition-all active:scale-95">
<button onClick={(e) => { e.stopPropagation(); toggleScreen(); }} aria-label="Share Screen" className="p-2 rounded-full bg-white/10 text-white transition-all active:scale-95">
<Monitor className="w-5 h-5" />
</button>
</div>
Expand Down Expand Up @@ -121,6 +121,7 @@ export function VideoGrid({
!canToggleMic && "opacity-50 cursor-not-allowed"
)}
title={isMicOn ? "Mute Microphone" : "Unmute Microphone"}
aria-label={isMicOn ? "Mute Microphone" : "Unmute Microphone"}
>
{isMicOn ? <Mic className="w-5 h-5" /> : <MicOff className="w-5 h-5" />}
</button>
Expand All @@ -136,6 +137,7 @@ export function VideoGrid({
!canToggleCam && "opacity-50 cursor-not-allowed"
)}
title={isCamOn ? "Turn Camera Off" : "Turn Camera On"}
aria-label={isCamOn ? "Turn Camera Off" : "Turn Camera On"}
>
{isCamOn ? <Video className="w-5 h-5" /> : <VideoOff className="w-5 h-5" />}
</button>
Expand All @@ -148,6 +150,7 @@ export function VideoGrid({
!canToggleScreen && "opacity-50 cursor-not-allowed"
)}
title="Share Screen"
aria-label="Share Screen"
>
<Monitor className="w-5 h-5" />
</button>
Expand Down