Skip to content

fix(a11y): add aria-label to duration abbreviations for screen readers#29806

Open
okxint wants to merge 2 commits into
calcom:mainfrom
okxint:fix/screen-reader-duration-aria-label
Open

fix(a11y): add aria-label to duration abbreviations for screen readers#29806
okxint wants to merge 2 commits into
calcom:mainfrom
okxint:fix/screen-reader-duration-aria-label

Conversation

@okxint

@okxint okxint commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

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 badge
  • EventTypeDescription.tsx — event listing duration badge
  • EventTypeListItem.tsx (atoms) — platform atoms event listing

New utilities:

  • getDurationAriaLabel(mins, t) in Duration.tsx — localized, uses existing i18n keys (minute_one, minute_other, hour_one, hour_other)
  • formatEventTypeDurationAriaLabel(minutes) in formatEventTypeDuration.ts — pure English for the atoms layer (no i18n dependency)

Tests added for formatEventTypeDurationAriaLabel covering all cases (minutes only, hours only, mixed, zero).

okxint added 2 commits July 4, 2026 11:01
…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.
@github-actions

Copy link
Copy Markdown
Contributor

Welcome to Cal.diy, @okxint! Thanks for opening this pull request.

A few things to keep in mind:

  • This is Cal.diy, not Cal.com. Cal.diy is a community-driven, fully open-source fork of Cal.com licensed under MIT. Your changes here will be part of Cal.diy — they will not be deployed to the Cal.com production app.
  • Please review our Contributing Guidelines if you haven't already.
  • Make sure your PR title follows the Conventional Commits format.

A maintainer will review your PR soon. Thanks for contributing!

@github-actions github-actions Bot added the 🐛 bug Something isn't working label Jul 20, 2026
@coderabbitai

coderabbitai Bot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Duration 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)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the accessibility fix for duration abbreviations.
Description check ✅ Passed The description matches the implemented aria-label changes and updated duration utilities.
Linked Issues check ✅ Passed The PR addresses #29750 by adding screen-reader-friendly labels to duration displays while preserving the visible abbreviations.
Out of Scope Changes check ✅ Passed The changes stay focused on duration accessibility, and the Hebrew locale tweak supports the new localized labels.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

📥 Commits

Reviewing files that changed from the base of the PR and between f004349 and 851bd60.

📒 Files selected for processing (7)
  • apps/web/modules/bookings/components/BookEventForm/BookFormAsModal.tsx
  • apps/web/modules/bookings/components/event-meta/Duration.tsx
  • apps/web/modules/event-types/components/EventTypeDescription.tsx
  • packages/i18n/locales/he/common.json
  • packages/platform/atoms/event-types/__tests__/formatEventTypeDuration.test.ts
  • packages/platform/atoms/event-types/components/EventTypeListItem.tsx
  • packages/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". */

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 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

@CLAassistant

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🐛 bug Something isn't working size/L

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Duration abbreviations pronounced incorrectly by screen readers ("30m" as "30 metres", "1h" as "one age")

2 participants