From 91ea1f9793738a416bb3bb1313bdd6a247686148 Mon Sep 17 00:00:00 2001 From: Orr Gottlieb Date: Fri, 22 May 2026 10:32:38 +0100 Subject: [PATCH] fix(a11y): repair broken aria-label, conflicting Toast role, and missing focus indicators - ColorPicker: aria-labelledby was set to literal text instead of an ID, leaving the dialog with no accessible name for screen readers; switched to aria-label and removed the same-shaped aria-describedby bug. - Toast: role="alert" (implicit assertive) combined with aria-live="polite" produced conflicting semantics across screen readers; switched to role="status" (implicit polite) and dropped the explicit aria-live. - Focus indicators: replaced bare ":focus { outline: none }" with the ":focus:not(:focus-visible)" pattern in Dialog, DialogContentContainer, AvatarGroupCounterTooltipContent (+ virtualized variant), BreadcrumbContent, Menu, and Tab so keyboard focus rings are no longer suppressed. Co-Authored-By: Claude Opus 4.7 --- .../DialogContent/DialogContent.module.scss | 2 +- .../DialogContentContainer.module.scss | 2 +- ...atarGroupCounterTooltipContent.module.scss | 4 +-- ...rTooltipContentVirtualizedList.module.scss | 4 +-- .../BreadcrumbContent.module.scss | 2 +- .../components/ColorPicker/ColorPicker.tsx | 3 +- .../__snapshots__/ColorPicker.test.tsx.snap | 5 ++-- .../src/components/Menu/Menu/Menu.module.scss | 2 +- .../src/components/Tabs/Tab/Tab.module.scss | 2 +- packages/core/src/components/Toast/Toast.tsx | 3 +- .../Toast.snapshot.test.tsx.snap | 30 +++++++------------ 11 files changed, 22 insertions(+), 37 deletions(-) diff --git a/packages/components/dialog/src/Dialog/components/DialogContent/DialogContent.module.scss b/packages/components/dialog/src/Dialog/components/DialogContent/DialogContent.module.scss index 9638037113..b0277ba4f9 100644 --- a/packages/components/dialog/src/Dialog/components/DialogContent/DialogContent.module.scss +++ b/packages/components/dialog/src/Dialog/components/DialogContent/DialogContent.module.scss @@ -44,7 +44,7 @@ pointer-events: none; } -.contentComponent:focus { +.contentComponent:focus:not(:focus-visible) { outline: none; } diff --git a/packages/components/dialog/src/DialogContentContainer/DialogContentContainer.module.scss b/packages/components/dialog/src/DialogContentContainer/DialogContentContainer.module.scss index 9a926dc690..732a0bf2f5 100644 --- a/packages/components/dialog/src/DialogContentContainer/DialogContentContainer.module.scss +++ b/packages/components/dialog/src/DialogContentContainer/DialogContentContainer.module.scss @@ -1,4 +1,4 @@ -.dialogContentContainer:focus { +.dialogContentContainer:focus:not(:focus-visible) { outline: none; } diff --git a/packages/core/src/components/AvatarGroup/AvatarGroupCounterTooltipContent.module.scss b/packages/core/src/components/AvatarGroup/AvatarGroupCounterTooltipContent.module.scss index 354d446ba1..abca45fd0d 100644 --- a/packages/core/src/components/AvatarGroup/AvatarGroupCounterTooltipContent.module.scss +++ b/packages/core/src/components/AvatarGroup/AvatarGroupCounterTooltipContent.module.scss @@ -15,9 +15,7 @@ overflow-x: visible; overflow-y: auto; margin-top: var(--space-8); - &:focus, - &:focus-visible, - &.focus-visible { /* stylelint-disable-line selector-class-pattern */ + &:focus:not(:focus-visible) { outline: none; } } diff --git a/packages/core/src/components/AvatarGroup/AvatarGroupCounterTooltipContentVirtualizedList.module.scss b/packages/core/src/components/AvatarGroup/AvatarGroupCounterTooltipContentVirtualizedList.module.scss index 6f6e138576..24f7838444 100644 --- a/packages/core/src/components/AvatarGroup/AvatarGroupCounterTooltipContentVirtualizedList.module.scss +++ b/packages/core/src/components/AvatarGroup/AvatarGroupCounterTooltipContentVirtualizedList.module.scss @@ -9,9 +9,7 @@ display: flex; overflow-y: hidden; overflow-x: visible; - &:focus, - &:focus-visible, - &.focus-visible { /* stylelint-disable-line selector-class-pattern */ + &:focus:not(:focus-visible) { outline: none; } } diff --git a/packages/core/src/components/BreadcrumbsBar/BreadcrumbItem/BreadcrumbContent/BreadcrumbContent.module.scss b/packages/core/src/components/BreadcrumbsBar/BreadcrumbItem/BreadcrumbContent/BreadcrumbContent.module.scss index de056f1a16..0665880865 100644 --- a/packages/core/src/components/BreadcrumbsBar/BreadcrumbItem/BreadcrumbContent/BreadcrumbContent.module.scss +++ b/packages/core/src/components/BreadcrumbsBar/BreadcrumbItem/BreadcrumbContent/BreadcrumbContent.module.scss @@ -37,7 +37,7 @@ a.breadcrumbContent:hover { flex-shrink: 0; } -.breadcrumbContent:focus { +.breadcrumbContent:focus:not(:focus-visible) { outline: none; } diff --git a/packages/core/src/components/ColorPicker/ColorPicker.tsx b/packages/core/src/components/ColorPicker/ColorPicker.tsx index 9d338b7de7..cbd23eb305 100644 --- a/packages/core/src/components/ColorPicker/ColorPicker.tsx +++ b/packages/core/src/components/ColorPicker/ColorPicker.tsx @@ -132,8 +132,7 @@ const ColorPicker = forwardRef( diff --git a/packages/core/src/components/ColorPicker/__tests__/__snapshots__/ColorPicker.test.tsx.snap b/packages/core/src/components/ColorPicker/__tests__/__snapshots__/ColorPicker.test.tsx.snap index 3b89c2dd8c..2de15e7460 100644 --- a/packages/core/src/components/ColorPicker/__tests__/__snapshots__/ColorPicker.test.tsx.snap +++ b/packages/core/src/components/ColorPicker/__tests__/__snapshots__/ColorPicker.test.tsx.snap @@ -2,8 +2,9 @@ exports[`renders correctly with empty props 1`] = `
{iconElement &&
{iconElement}
} diff --git a/packages/core/src/components/Toast/__tests__/__snapshots__/Toast.snapshot.test.tsx.snap b/packages/core/src/components/Toast/__tests__/__snapshots__/Toast.snapshot.test.tsx.snap index 5bbf6beb9c..a20aa9538e 100644 --- a/packages/core/src/components/Toast/__tests__/__snapshots__/Toast.snapshot.test.tsx.snap +++ b/packages/core/src/components/Toast/__tests__/__snapshots__/Toast.snapshot.test.tsx.snap @@ -2,10 +2,9 @@ exports[`Toast renders correctly > (renders nothing) with empty props 1`] = `
(renders nothing) with empty props 1`] = ` exports[`Toast renders correctly > and don't renders close button if closeable=false 1`] = `
and don't renders close button if closeable=f exports[`Toast renders correctly > renders nothing when open is false 1`] = `
renders nothing when open is false 1`] = ` exports[`Toast renders correctly > when icon is hidden 1`] = `
when icon is hidden 1`] = ` exports[`Toast renders correctly > when open is true 1`] = `
when open is true 1`] = ` exports[`Toast renders correctly > with button 1`] = `
with button 1`] = ` exports[`Toast renders correctly > with button and link 1`] = `
with button and link 1`] = ` exports[`Toast renders correctly > with link 1`] = `
with link 1`] = ` exports[`Toast renders correctly > with loading 1`] = `
with loading 1`] = ` exports[`Toast renders correctly > with negative type 1`] = `