fix(a11y): call toggles no longer contradict their labels (#187 DP7/8)
CI / Build & Quality Checks (push) Successful in 2m9s
CI / Docker image build & smoke test (push) Skipped
CI / Secret scan (gitleaks) (push) Successful in 9s
CI / Trigger Desktop Build (push) Successful in 3s
CI / Playwright smoke (e2e) (push) Successful in 10m15s

The call-bar and status-bar toggles change their label with the state
("Deafen"/"Undeafen", "Turn off/on microphone", "Start/Stop Video", …)
AND set aria-pressed, which made screen readers say "Deafen, pressed"
while you were not deafened, and gave mic/screenshare a pressed state in
one bar but not the other. Per the ARIA practice, a toggle uses either a
changing action label or aria-pressed with a fixed label; these use the
former, so aria-pressed is removed from all nine.

Checked in a live call: every control now announces only its action, in
both states (deafen → "Undeafen", mic → "Turn on microphone", …).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PPmy3tPq869XDW4njjVaKA
This commit is contained in:
Lotus CI
2026-09-24 11:59:45 -04:00
co-authored by Claude Opus 5.5
parent ed87b700d9
commit c0a9b2da6b
2 changed files with 6 additions and 9 deletions
+3 -4
View File
@@ -40,7 +40,6 @@ function MicrophoneButton({ enabled, onToggle, disabled }: MicrophoneButtonProps
outlined
disabled={disabled || loading}
aria-label={enabled ? 'Turn off microphone' : 'Turn on microphone'}
aria-pressed={enabled}
>
<Icon size="100" src={enabled ? Icons.Mic : Icons.MicMute} filled={!enabled} />
</IconButton>
@@ -73,8 +72,10 @@ function SoundButton({ enabled, onToggle, disabled }: SoundButtonProps) {
size="300"
className={MobileTouchTarget}
onClick={() => onToggle()}
// No aria-pressed on these call toggles (#187 DP7/8): their labels already
// name the action ("Deafen" / "Undeafen"), and pressed-state on top
// read as "Deafen, pressed" while NOT deafened.
aria-label={enabled ? 'Deafen' : 'Undeafen'}
aria-pressed={enabled}
outlined
disabled={disabled}
>
@@ -117,7 +118,6 @@ function VideoButton({ enabled, onToggle, disabled }: VideoButtonProps) {
className={MobileTouchTarget}
onClick={toggleVideo}
aria-label={enabled ? 'Stop Video' : 'Start Video'}
aria-pressed={enabled}
outlined
disabled={disabled || loading}
>
@@ -157,7 +157,6 @@ function ScreenShareButton({ enabled, onToggle, disabled }: ScreenShareButtonPro
className={MobileTouchTarget}
onClick={onToggle}
aria-label={enabled ? 'Stop Screenshare' : 'Start Screenshare'}
aria-pressed={enabled}
outlined
disabled={disabled}
>
+3 -5
View File
@@ -74,8 +74,10 @@ export function SoundButton({ enabled, onToggle }: SoundButtonProps) {
size="400"
className={MobileTouchTarget}
onClick={() => onToggle()}
// No aria-pressed on these call toggles (#187 DP7/8): their labels already
// name the action ("Deafen" / "Undeafen"), and pressed-state on top
// read as "Deafen, pressed" while NOT deafened.
aria-label={enabled ? 'Deafen' : 'Undeafen'}
aria-pressed={enabled}
outlined
>
<Icon
@@ -124,7 +126,6 @@ export function VideoButton({ enabled, onToggle, disabled }: VideoButtonProps) {
aria-label={
disabled ? 'Camera disabled in settings' : enabled ? 'Stop camera' : 'Start camera'
}
aria-pressed={enabled}
style={disabled ? { opacity: 0.4, cursor: 'not-allowed' } : undefined}
>
<Icon
@@ -209,7 +210,6 @@ export function FullscreenButton({ isFullscreen, onToggle }: FullscreenButtonPro
className={MobileTouchTarget}
onClick={onToggle}
aria-label={isFullscreen ? 'Exit Fullscreen' : 'Fullscreen'}
aria-pressed={isFullscreen}
outlined
>
{isFullscreen ? <ExitFullscreenIcon /> : <FullscreenIcon />}
@@ -244,7 +244,6 @@ export function ScreenshareAudioButton({ muted, onToggle }: ScreenshareAudioButt
className={MobileTouchTarget}
onClick={onToggle}
aria-label={muted ? 'Unmute Screenshare Audio' : 'Mute Screenshare Audio'}
aria-pressed={muted}
outlined
>
<Icon size="400" src={muted ? Icons.VolumeMute : Icons.VolumeHigh} filled={muted} />
@@ -277,7 +276,6 @@ export function ChatButton() {
className={MobileTouchTarget}
onClick={() => setChat(!chat)}
aria-label={chat ? 'Close Chat' : 'Open Chat'}
aria-pressed={chat}
outlined
>
<Icon size="400" src={Icons.Message} filled={chat} />