RadioListItem and CheckboxListItem accept rich label and description content - #5257
Draft
cixzhang wants to merge 1 commit into
Draft
RadioListItem and CheckboxListItem accept rich label and description content#5257cixzhang wants to merge 1 commit into
cixzhang wants to merge 1 commit into
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
RadioListItem typed label and description as string while CheckboxListItem already typed label as ReactNode, so the two disagreed about the same slot and neither could hold a description with a link in it. The runtime rendered ReactNode fine; only the types refused. RadioListItem also gains the aria-label escape hatch CheckboxListItem established, applied to the radio control rather than the row.
cixzhang
force-pushed
the
radiolist-node-label
branch
from
August 20, 2026 17:30
5f03b74 to
10009ff
Compare
Contributor
PR Analysis Report📚 Storybook PreviewView Storybook for this PR 🧪 Sandbox PreviewView Sandbox for this PR Modified ComponentsCheckboxList (@astryxdesign/core) · View in Storybook
RadioList (@astryxdesign/core) · View in Storybook
Bundle Size Summary
Accessibility AuditStatus: 2 accessibility violation(s) found — 2 serious. CheckboxList - 1 issue(s)
RadioList - 1 issue(s)
Generated by PR Enrichment workflow | Storybook | Sandbox | View full report |
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.
Why
RadioListItemtypeslabelanddescriptionasstring. Its siblingCheckboxListItemalready typeslabelasReactNode, so radio and checkbox disagree about the same slot — and an app whose option descriptions carry a link can type one on neither.The runtime was never the obstacle.
ItemandListItemhave takenReactNodefor both slots all along, so a rich node already rendered and the label element already named the radio from its own text. Only the types refused.What
labelonRadioListItem, anddescriptionon both items, are nowReactNode.RadioListItempicks up thearia-labelescape hatchCheckboxListItemestablished, with the same meaning: a plain-text accessible name applied to the control, not the row.The two controls reach that name by different routes, and the prop docs say so rather than pretending they match:
CheckboxListItem's checkbox carries its own visually hidden label, so a richlabelleaves it named "Checkbox" — it warns in dev until you passaria-label.RadioListItem's<label htmlFor>wraps the visible content and is tied to the input, so a rich label still computes a name from its text.aria-labelnarrows a name that reads badly, rather than rescuing a missing one, so there is no dev warning here — it would fire on labels that are already named correctly.One caveat now documented on the prop:
labelsits inside the<label>element, so interactive content there would also select the radio. Links belong indescriptionorendContent, both outside it — which is what the motivating case wants anyway.Left alone deliberately.
RadioListandCheckboxListkeeplabel: stringanddescription?: string. Those are the group's field-level label and helper text, owned byFieldand shared with every input that composes it; widening them is a change toField's contract alongsideisLabelHiddenandlabelTooltip, with its own accessible-name story. Different change.Risk
One behavior change:
aria-labelonRadioListItemused to land on the row<div>, where ARIA ignores it on a role-less element. It now names the radio. Every otheraria-*still forwards to the row, matchingCheckboxListItem.Widening
descriptionalso made a latent guard mismatch reachable, so it is fixed here: the description element was guarded by!= nullwhile itsaria-describedbyused truthiness, and the ordinaryflag && <span>…</span>idiom yieldsfalse— enough to render an empty described-by target. Both now go throughisRenderable.Testing
Core suite (7057 tests),
typecheck,typecheck:docsand lint all green. New unit tests cover the name computed from a rich label,aria-labeloverriding it, a rich label still selecting on click, a link in a description staying outside the<label>, and an empty description leavingaria-describedbyoff.jsdom cannot settle accessible names, so the a11y half was read out of Chromium's own accessibility tree against the new stories:
Pro <Badge label="Popular" />, noaria-labelPro Populararia-label="Pro"Pro$12 per seat. See what is includedStarterFree forever. Compare plansPersonalizationInteraction in the same browser: clicking a rich label selects its radio; clicking a link inside a description selects nothing, on radio and checkbox alike, while a click on the rest of the checkbox row still toggles it.