Improve badge accessibility and fix icon-only rendering

Add warning when text parameter is missing and icon_only is true. Hide icons from screen readers when badge has both icon and text. Fix bug where icon_only didn't actually hide text visually. Update Lookbook preview to demonstrate correct usage.

Changelog: changed

What does this MR do and why?

Improves accessibility for the Pajamas::BadgeComponent by:

  1. Adding a warning when icon_only: true is used without the text parameter - the text becomes the aria-label for screen readers
  2. Hiding icons from screen readers when badge has both icon and text by setting aria_label="" on the icon
  3. Fixing bug where icon_only: true didn't actually hide the text visually
  4. Updating Lookbook preview example to demonstrate correct icon-only usage

Why: Icon-only badges need accessible labels for screen readers. The text parameter provides this label, so it must be required when icon_only: true.

No existing instances are impacted because a codebase search found zero usages of icon_only: true in application code. The parameter exists in the API but has never been used outside of test specs (which already provide the required text parameter). This means the validation and bug fix only affect future usage.

References

Relates to gitlab-org/gitlab-services/design.gitlab.com#3197

Usage guidelines updated in gitlab-org/gitlab-services/design.gitlab.com!5370

Screenshots or screen recordings

Before After
Screenshot 2025-11-21 at 16.10.11.png Screenshot 2025-11-21 at 16.08.57.png
Screenshot 2025-11-21 at 16.10.22.png Screenshot 2025-11-21 at 16.08.03.png

Preview in Lookbook: http://127.0.0.1:3000/rails/lookbook/inspect/pajamas/badge/

Toggle icon_only to see the badge with only an icon and proper aria-label.

How to set up and validate locally

  1. Start Lookbook locally
  2. Navigate to http://127.0.0.1:3000/rails/lookbook/inspect/pajamas/badge/
  3. Toggle icon_only to true and verify:
    • Text is hidden visually
    • Badge has role="img" and aria-label with the text value
  4. Try creating a badge with icon_only: true but no text parameter - should raise ArgumentError

Non breaking changes

This MR logs a warning (not an error) when icon_only: true is used without a text parameter. Existing code will continue to work, but developers will be alerted to add proper accessibility labels.

Impact: No migrations needed. Search of the codebase shows no existing usages of icon_only: true in application code (only in test specs, which already provide text).

Migration path:

# Before (will log a warning)
render Pajamas::BadgeComponent.new(icon: 'calendar', icon_only: true)

# After
render Pajamas::BadgeComponent.new(icon: 'calendar', icon_only: true, text: 'Due date')

The text should describe what the metadata represents, not just the icon name.

MR acceptance checklist

Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.

Edited by Dan MH

Merge request reports

Loading