fix(a11y): add aria-label to duration abbreviations for screen readers#29806
fix(a11y): add aria-label to duration abbreviations for screen readers#29806okxint wants to merge 2 commits into
Conversation
…on strings Closes calcom#29694 `minute_one_short` and `hour_one_short` were missing a space between the interpolated count and the Hebrew unit abbreviation, producing outputs like "15ד'" and "2ש'" instead of "15 ד'" and "2 ש'".
Duration values like "30m" and "1h 30m" are announced literally by
screen readers, which is unintelligible. Wrapping them in a span with
an aria-label of the full phrase ("30 minutes", "1 hour 30 minutes")
gives assistive technology a meaningful label while keeping the
abbreviated display for sighted users.
Covers: booking page EventDuration component, hidden-selector variant,
duration picker buttons, booking confirmation modal badge, event listing
EventTypeDescription, and platform atoms EventTypeListItem.
|
Welcome to Cal.diy, @okxint! Thanks for opening this pull request. A few things to keep in mind:
A maintainer will review your PR soon. Thanks for contributing! |
📝 WalkthroughWalkthroughDuration formatting now includes screen-reader-friendly aria-labels across event type lists, booking forms, duration selectors, and event descriptions. New helpers format minute and hour values with singular/plural wording, and tests cover minute-only, hour-only, and combined durations. Hebrew short singular minute and hour translations were also updated to include spacing. 🚥 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: 1
🤖 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: Replace the JSDoc for the duration aria-label function in
apps/web/modules/bookings/components/event-meta/Duration.tsx at lines 40-40 with
a why-focused explanation about using fully expanded duration words for
assistive technologies. In
packages/platform/atoms/event-types/lib/formatEventTypeDuration.ts at lines
27-36, remove the redundant first JSDoc line describing what the function
returns and retain the existing rationale.
🪄 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: 33cbcc6e-1690-4097-aa53-556e0b4890ba
📒 Files selected for processing (7)
apps/web/modules/bookings/components/BookEventForm/BookFormAsModal.tsxapps/web/modules/bookings/components/event-meta/Duration.tsxapps/web/modules/event-types/components/EventTypeDescription.tsxpackages/i18n/locales/he/common.jsonpackages/platform/atoms/event-types/__tests__/formatEventTypeDuration.test.tspackages/platform/atoms/event-types/components/EventTypeListItem.tsxpackages/platform/atoms/event-types/lib/formatEventTypeDuration.ts
| return hourStr || minStr; | ||
| }; | ||
|
|
||
| /** Returns a screen-reader-friendly label for a duration, e.g. "30 minutes" or "1 hour 30 minutes". */ |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Remove comments that restate what the code does.
As per coding guidelines, code comments should only explain why, not what, and must never simply restate what the code does. Both of the new duration aria-label functions have JSDoc comments that describe what the function does (returning a screen-reader-friendly label).
apps/web/modules/bookings/components/event-meta/Duration.tsx#L40-L40: Replace the comment with an explanation of why this function exists (e.g.,/** Uses fully expanded duration words so assistive technologies read durations correctly instead of mispronouncing abbreviations. */).packages/platform/atoms/event-types/lib/formatEventTypeDuration.ts#L27-L36: Remove the first line (* Returns a screen-reader-friendly label for a duration.) since the subsequent line correctly explains the why.
📍 Affects 2 files
apps/web/modules/bookings/components/event-meta/Duration.tsx#L40-L40(this comment)packages/platform/atoms/event-types/lib/formatEventTypeDuration.ts#L27-L36
🤖 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,
Replace the JSDoc for the duration aria-label function in
apps/web/modules/bookings/components/event-meta/Duration.tsx at lines 40-40 with
a why-focused explanation about using fully expanded duration words for
assistive technologies. In
packages/platform/atoms/event-types/lib/formatEventTypeDuration.ts at lines
27-36, remove the redundant first JSDoc line describing what the function
returns and retain the existing rationale.
Source: Coding guidelines
|
|
Fixes #29750
Duration values like "30m" and "1h 30m" are announced literally by screen readers ("thirty m", "one h thirty m"), which is unintelligible to blind users.
Fix: wrap each duration display in a
<span aria-label="...">that spells out the full phrase. Visual display is unchanged.Covered locations:
Duration.tsx— EventDuration component (single duration, hidden-selector, and duration picker buttons)BookFormAsModal.tsx— booking confirmation modal duration badgeEventTypeDescription.tsx— event listing duration badgeEventTypeListItem.tsx(atoms) — platform atoms event listingNew utilities:
getDurationAriaLabel(mins, t)inDuration.tsx— localized, uses existing i18n keys (minute_one,minute_other,hour_one,hour_other)formatEventTypeDurationAriaLabel(minutes)informatEventTypeDuration.ts— pure English for the atoms layer (no i18n dependency)Tests added for
formatEventTypeDurationAriaLabelcovering all cases (minutes only, hours only, mixed, zero).