fix: a11y baseline pass across components#805
Draft
paanSinghCoder wants to merge 1 commit into
Draft
Conversation
Address the cross-component a11y gaps tracked in #673 with one PR. Each change is targeted at the specific WCAG / ARIA issue called out in the child issues — no broader refactors. Component-level fixes - Tooltip: aria-label / aria-labelledby flow to Popup for ReactNode messages - TextArea: aria-invalid / aria-required propagated from Field context - Table: Table.Head defaults scope="col"; SectionHeader uses scope="colgroup"; new Table.Caption sub-component - Spinner: drop conflicting aria-hidden + status combo; add ariaLabel (default "Loading"); aria-hidden override cleanly demotes to decorative - Skeleton: aria-hidden="true" on decorative placeholder container - Sidebar: remove orphan role="listitem" (items rely on native element semantics) - SidePanel: title renders as <h2> with generated id, new titleId prop for aria-labelledby wiring - Drawer: aria-label / aria-labelledby customisable; new closeLabel prop (default "Close") - Separator: new `decorative` prop -> role="presentation" + aria-hidden - Select: remove conflicting aria-multiselectable on Combobox list (data-multiselectable retained for styling) - ScrollArea: aria-label / aria-labelledby apply role="region" to viewport - List: keep explicit role="list" (Safari drops implicit role when list-style:none); drop redundant role="listitem"; remove generic default aria-label="List"; new `level` prop on List.Header (default 3, was hardcoded) - Link: drop redundant role="link"; use children for aria-label only when string (no more "[object Object]") - Label: new requiredText + showRequiredIndicator props to balance the existing (optional) indicator - Input: aria-invalid / aria-required from Field context; leading / trailing icon wrappers marked aria-hidden - Image: drop redundant role="img" and aria-label={alt} (native alt is the accessible name) - IconButton: drop redundant aria-disabled; strengthen aria-label guidance in JSDoc - Container: no default role="region"; role applied only when an aria-label / aria-labelledby is supplied - Button: aria-busy when loading; internal spinner marked aria-hidden so the button speaks for itself - AnnouncementBar: action rendered as a real <button> with focus styles (was <Text onClick>); decorative icons aria-hidden Tests + docs - Existing component tests updated to assert the corrected a11y contract (1735 passing, +28 vs. main). - props.ts updated for every new prop (Spinner.ariaLabel, Drawer.closeLabel, Separator.decorative, List.Header.level, Label.requiredText / showRequiredIndicator, SidePanel.Header.titleId, Table.Head.scope + Table.Caption, Tooltip.Content aria-label / aria-labelledby). - Accessibility sections in index.mdx rewritten where the previous text claimed roles / attributes that are no longer emitted. Behavioural notes for downstream consumers - getByRole('listitem') will not find Sidebar items or List items. - getByRole('img') will not find decorative (alt="") images. - getByRole('region') will not find a Container without a label. - getByLabelText('Close Drawer') is now getByLabelText('Close') (override via closeLabel for older copy). - Test suites that depended on these strings will need a small update.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Contributor
|
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Address the cross-component accessibility gaps tracked in #673 in one PR. Each fix is targeted at the specific WCAG / ARIA issue from the child issues (#596, #600 already fixed, #601, #605 already fixed, #610, #620, #621, #623, #624, #625, #626, #631, #633, #634, #635, #636, #637, #638, #639 already fixed, #640, #642, #643 already fixed, #645, #647 already fixed, #648) — no broader refactors.
Component changes (21 source files):
aria-label/aria-labelledbyflow to Popup so ReactNode messages get an accessible namearia-invalid/aria-requiredpropagated from Field contextTable.Headdefaultsscope=\"col\"; SectionHeader usesscope=\"colgroup\"; newTable.Captionaria-hidden+role=\"status\"; addariaLabel(default\"Loading\");aria-hiddenoverride demotes to decorative cleanlyaria-hidden=\"true\"on decorative placeholder containerrole=\"listitem\"<h2>with generated id; newtitleIdprop foraria-labelledbyaria-label/aria-labelledbycustomisable; newcloseLabelprop (default\"Close\")decorativeprop →role=\"presentation\"+aria-hiddenaria-multiselectableon Combobox list (data-multiselectableretained for styling)aria-label/aria-labelledbyapplyrole=\"region\"to viewportrole=\"list\"(Safari drops the implicit role underlist-style: none); drop redundantrole=\"listitem\"; remove generic defaultaria-label=\"List\"; newlevelprop onList.Headerrole=\"link\"; usechildrenfor aria-label only when it's a stringrequiredText+showRequiredIndicatorprops to balance the existing(optional)indicatoraria-invalid/aria-requiredfrom Field context; leading / trailing icon wrappersaria-hiddenrole=\"img\"andaria-label={alt}(nativealtis the accessible name)aria-disabled; strengthenaria-labelguidance in JSDocrole=\"region\"; role applied only when anaria-label/aria-labelledbyis suppliedaria-busywhenloading; internal spinner markedaria-hiddenso the button speaks for itself<button>with focus styles (was<Text onClick>); decorative iconsaria-hiddenTests + docs:
apps/wwwprops.tsupdated for every new prop.apps/wwwAccessibility sections rewritten where the previous text claimed roles / attributes that are no longer emitted.Behavioural changes downstream callers should know about
Bumping to this version is mostly a drop-in, but a few queries / assertions need updating:
getByRole('listitem')no longer finds Sidebar or List items — they rely on native element semantics now.getByRole('img')does not find decorative images (alt=\"\").getByRole('region')no longer finds aContainerunless anaria-label/aria-labelledbyis supplied.getByLabelText('Close Drawer')is nowgetByLabelText('Close')(override via thecloseLabelprop if the old copy is needed).getByRole('status')to detect a Button's loading state should switch toexpect(button).toHaveAttribute('aria-busy', 'true').Test plan
pnpm test:apsara— 1735 / 1735 passing locallypnpm --filter @raystack/apsara build— cleanSidePanel.Header(now<h2>— confirm default heading margins don't shift layout)AnnouncementBaraction (now<button>with reset CSS + focus ring — confirm rendering is unchanged)aria-multiselectabledoesn't regress AT announcementsCloses #673.