fix: add aria-label to duration abbreviations for screen reader accessibility#29763
fix: add aria-label to duration abbreviations for screen reader accessibility#29763prathamesh04 wants to merge 1 commit into
Conversation
…sibility Screen readers announce '30m' as '30 metres' and '1h' as 'one age' instead of '30 minutes' and '1 hour'. Added a getDurationAccessibilityLabel function that returns the full expanded text and applied it as aria-label to all duration display elements. Fixes calcom#29750 Signed-off-by: Prathamesh Hukkeri <prathamesh04@users.noreply.github.com>
|
Welcome to Cal.diy, @prathamesh04! Thanks for opening this pull request. A few things to keep in mind:
A maintainer will review your PR soon. Thanks for contributing! |
📝 WalkthroughWalkthroughAdded a localized helper that expands minute durations into screen-reader-friendly hour and minute text. Applied the generated labels to event duration displays, hidden-selector displays, selectable duration options, and the booking modal duration badge. 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@apps/web/modules/bookings/components/event-meta/Duration.tsx`:
- Line 40: Rewrite the comment above the duration accessibility helper to
explain that a separate expanded label is provided for screen readers, rather
than describing the text it returns; alternatively, remove the comment if the
rationale is clear from the surrounding code.
- Line 114: Update the selectable duration rendering in Duration.tsx so each
clickable option uses a real button containing the duration label and
interaction handler, while retaining the li wrapper only as needed. Preserve the
passive duration badge in BookFormAsModal.tsx as plain text.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 01d86d80-4ba8-4daf-9e46-6c3a753e3cc6
📒 Files selected for processing (2)
apps/web/modules/bookings/components/BookEventForm/BookFormAsModal.tsxapps/web/modules/bookings/components/event-meta/Duration.tsx
| return hourStr || minStr; | ||
| }; | ||
|
|
||
| /** Returns the full expanded duration text for screen readers (e.g. "30 minutes", "1 hour 30 minutes") */ |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Rewrite the comment to explain why, not what.
This comment describes the helper’s behavior rather than why the separate accessibility label is needed. Prefer explaining the screen-reader requirement, or remove the comment.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@apps/web/modules/bookings/components/event-meta/Duration.tsx` at line 40,
Rewrite the comment above the duration accessibility helper to explain that a
separate expanded label is provided for screen readers, rather than describing
the text it returns; alternatively, remove the comment if the rationale is clear
from the surrounding code.
Source: Coding guidelines
|
|
||
| if (!event?.metadata?.multipleDuration && !isDynamicEvent) | ||
| return <>{getDurationFormatted(event.length, t)}</>; | ||
| return <span aria-label={getDurationAccessibilityLabel(event.length, t)}>{getDurationFormatted(event.length, t)}</span>; |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '\n== files ==\n'
git ls-files 'apps/web/modules/bookings/components/event-meta/Duration.tsx' 'apps/web/modules/bookings/components/BookFormAsModal.tsx' || true
printf '\n== Duration.tsx outline ==\n'
ast-grep outline apps/web/modules/bookings/components/event-meta/Duration.tsx --view expanded || true
printf '\n== BookFormAsModal.tsx outline ==\n'
ast-grep outline apps/web/modules/bookings/components/BookFormAsModal.tsx --view expanded || true
printf '\n== Duration.tsx targeted lines ==\n'
sed -n '1,240p' apps/web/modules/bookings/components/event-meta/Duration.tsx | cat -n | sed -n '1,240p'
printf '\n== BookFormAsModal.tsx targeted lines ==\n'
sed -n '1,180p' apps/web/modules/bookings/components/BookFormAsModal.tsx | cat -n | sed -n '1,180p'Repository: calcom/cal.diy
Length of output: 8535
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '\n== locate BookFormAsModal ==\n'
fd -a 'BookFormAsModal.tsx' apps web packages . 2>/dev/null | sed -n '1,20p'
printf '\n== search for duration label patterns ==\n'
rg -n 'aria-label=\{getDurationAccessibilityLabel|getDurationFormatted\(|multipleDuration|hideDurationSelectorInBookingPage' apps/web/modules/bookings -S
printf '\n== inspect likely BookFormAsModal locations ==\n'
for f in $(fd -a 'BookFormAsModal.tsx' . 2>/dev/null | sed -n '1,10p'); do
echo "--- $f ---"
wc -l "$f"
sed -n '1,160p' "$f" | cat -n | sed -n '1,160p'
doneRepository: calcom/cal.diy
Length of output: 7313
Make the selectable durations actual buttons
The clickable <li> options in apps/web/modules/bookings/components/event-meta/Duration.tsx aren’t keyboard-accessible. Move the interaction and label to a real <button> (keeping the <li> as a wrapper if needed) so selection works without a mouse. The passive duration badge in BookFormAsModal.tsx can stay as plain text.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@apps/web/modules/bookings/components/event-meta/Duration.tsx` at line 114,
Update the selectable duration rendering in Duration.tsx so each clickable
option uses a real button containing the duration label and interaction handler,
while retaining the li wrapper only as needed. Preserve the passive duration
badge in BookFormAsModal.tsx as plain text.
Overview
Screen readers announce duration abbreviations incorrectly — '30m' is read as '30 metres' and '1h' as 'one age' instead of '30 minutes' and '1 hour'. This PR adds aria-label attributes with the full expanded text to all duration display elements so screen readers announce them correctly.
Fixes #29750
Changes
getDurationAccessibilityLabelfunction inDuration.tsxthat returns the full expanded text (e.g. '30 minutes', '1 hour 30 minutes') using the existing i18n translation keys (minute_one,minute_other,hour_one,hour_other)aria-labelto:<li>elements)Technical Details
minute_one,minute_other,hour_one,hour_other) which already have the full text forms — no new translations neededgetDurationAccessibilityLabelfunction is exported so it can be reused in other components if neededTest plan
getDurationAccessibilityLabelreturns correct full text for various durations (30m → '30 minutes', 1h → '1 hour', 1h 30m → '1 hour 30 minutes')aria-labelis applied to all duration display elements