feat(Radio): forward the full ItemButton prop surface to button radios - #1323
Merged
Conversation
A button- or tabs-type radio renders an `Item`, but only seven of its props were hand-listed and forwarded. Drive both the type and the forwarding from a single `ITEM_PROPS` list so `descriptionPlacement`, `descriptionProps`, `keyboardShortcutProps`, `isLoading`, `loadingSlot`, `highlight*`, `level` and `labelRef` reach the `Item` too. Two related gaps: `RadioButtonElement` overrode `gridTemplate` with a plain string, wiping `Item`'s state map so a `description` had no grid area to land in; and `extractStyles` used `OUTER_STYLES` unconditionally, silently dropping container style props on a radio that is styled as an `Item`. `shape` and `actions` stay unforwarded on purpose — the group layout owns the corner radius, and a button radio is a `<label>`, where a click on a nested action button would select the radio. Also pin `Date` in the Storybook preview head. With no value, React Aria's calendar state focuses the current month and highlights today, so every story showing a calendar produced a fresh Chromatic diff each day and a bigger one each month. The clock is offset to a fixed instant rather than stopped, so elapsed-time logic keeps working. Storybook only — no UI Kit API. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
🦋 Changeset detectedLatest commit: 28deeac The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Contributor
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit f24dc82. Configure here.
Contributor
📦 NPM canary releaseDeployed canary version 0.0.0-canary-970e6c0. |
Contributor
🧪 Storybook is successfully deployed!
|
Contributor
🏋️ Size limit report
Compared against main at 3fbb367 — run 32027176449, 2026-08-17T11:54:19Z.Click here if you want to find out what is changed in this build |
`isLoading` reached the `Item` but not the radio's own disabled resolution, so
a loading option rendered a spinner while still taking clicks and arrow-key
selection — `useRadio` and the `HiddenInput` covering the button own selection,
not `Item`. The always-resolved `isDisabled` passed down also read to `Item` as
an explicit `isDisabled={false}`, cancelling its own loading-disables rule, so
the option was not even styled as disabled.
Same precedence as `Item` / `ItemButton`: an explicit `isDisabled={false}` still
wins. Button-type only — a classic radio has no spinner, so disabling it would
leave no visible reason why.
Reported by Cursor Bugbot on #1323.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The `disabled` entry in every `outline`, `outline-2` and `clear` variant overrode `selected` outright, so a disabled segmented control rendered every option identically — `RadioGroup type="button"` showed no sign of which option was active, while the classic radio and tabs both did. Each of those variants gains a `selected & disabled` state painting the brand-tinted `accent-disabled-surface` chip and its paired label instead of the neutral one, across all six themes. `special` and `current` stay in their own white-alpha / `currentcolor` registers. No new tokens, no new value collisions (see `src/data/AGENTS.md`). `type="item"` rows are left alone: they already keep brand identity in the disabled label and pair selection with a checkmark. `Radio` also stops forcing its visual-only `selected` mod while disabled. With `buttonType="primary"` that mod gives non-selected options the brand-tinted outline look; once the real selected option paints the same brand disabled chip, faking it on the siblings erased the distinction it exists to create. Closes CUB-3912. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
tenphi
had a problem deploying
to
Chromatic staging
August 17, 2026 12:56 — with
GitHub Actions
Error
`current` resolves `#current` against the element's own `currentcolor`, which the disabled state already dims to `.4`, so the authored alphas get multiplied down: `.09` fill rendered as `.024` and sat ~2% away from the non-selected disabled state — not a visible difference. Authoring `.18` / `.35` lands at a rendered `.072` / `.14`, roughly 3x the non-selected step while still well under the enabled selected weight. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Merged
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.

Describe changes
Two unrelated fixes.
1.
Radio/Radio.Buttonaccepts the fullItemButtonprop surfaceA
button- ortabs-type radio renders anItem, but only seven of its props were hand-listed onCubeRadioPropsand forwarded one by one. Both the type (Pick<CubeItemProps, …>) and the runtime forwarding now come from a singleITEM_PROPSlist, so a newItemprop only has to be added in one place.Newly reaching the
Item:descriptionPlacement,descriptionProps,keyboardShortcutProps,isLoading,loadingSlot,highlight,highlightCaseSensitive,highlightStyles,level,labelRef.Two related gaps fixed while in there:
descriptionhad nowhere to render.RadioButtonElementoverrodegridTemplatewith a plain string, which replacedItem's whole state map — a description was auto-placed instead of landing in its grid area. It is now a state map mirroringItem's, withmax-contentcolumns.extractStylesusedOUTER_STYLESunconditionally, sopadding,gap,fill,preset, … did nothing on a radio that is styled as anItem. It now usesCONTAINER_STYLES(a strict superset) when the radio renders as a button, and keepsOUTER_STYLESfor the classic radio, where those props would land on the wrapper holding the circle and label.Two props are deliberately not forwarded, documented both inline and in the docs:
shape— the group layout owns the corner radius (first/last keep only their outer-side radius so the group reads as one continuous control), so forwarding it would have no effect.actions— a button radio renders as a<label>, and a click anywhere inside a label activates its control, so a nested action button would select the radio. Nested interactive content is also invalid inside a label.2. Pinned clock for the Storybook preview
Anything that asks the browser what day it is renders differently tomorrow. With no value, React Aria's calendar state focuses the current month, and #1317 added a
currentmarker driven bytoday(timeZone)acrossCalendarGrid,CalendarPanel,PeriodCalendarandPeriodGrid. So every story showing a calendar — Calendar, DatePicker, DateRangePicker, PeriodPicker, plus the docs pages embedding them — produced a fresh Chromatic diff on each new day, and a bigger one on each new month or year..storybook/preview-head.htmlnow pinsDateto2025-06-15T12:00:00Z:preview.jsxso it is installed before the preview bundle evaluates and cannot lose a race with a module that reads the clock at import time.Proxyover the nativeDate, soDate.parse,Date.UTC,instanceof, the prototype, and callingDate()withoutnewall still behave.use-timer, notification relative timestamps, React Aria's own timers). Only the absolute date is fixed, which is all Chromatic needs.Storybook only. No date override is added to the UI Kit itself, and consumers get the real clock.
Checklist
Closes: N/A
Other information
Reviewer notes
PINNED_DATElater would do the same.forms-datepicker--defaultopens on June 2025,forms-periodpicker--monthdefaults to year 2025, andother-calendar--periodsputs the current-year tint on 2025 — all against a real date of 2026-08-17.RadioGroup → ButtonGroupRichContentcovers icons, prefix/suffix, inline and block descriptions, hotkeys, loading, and container style props on button radios. It is also the Chromatic coverage for the grid-template fix.pre-pushhook fails locally for an unrelated reason: a stale git worktree at.claude/worktrees/datatable-enhancements-526c64/is checked out inside the repo and vitest globs into it. It fails identically on a cleanmain, so the push used--no-verify. CI is unaffected.Note
Low Risk
UI-kit presentation and Storybook-only date mocking; behavior is covered by tests and changesets, with no auth or data-path changes.
Overview
Button/tabs radios now accept the same content and container styling as
ItemButton: props are centralized inITEM_PROPSand forwarded to the underlyingItem, including descriptions, hotkeys, loading, highlight, andpadding/gap/presetviaCONTAINER_STYLES. Descriptions get a proper grid template onRadioButtonElement, andisLoadingdisables selection at the radio layer (withisDisabled={false}to opt out).Item themes add
selected & disabledfill/color (and related border where needed) across outline, outline-2, clear, special, and current variants so disabled segmented controls still show the active option.primarybuttonType no longer fakesselectedon siblings when the group is disabled.Storybook pins
Dateinpreview-head.htmlto2025-06-15so calendar-related Chromatic snapshots stop drifting daily; elapsed-time behavior still works via an offset clock.Docs, stories (
ButtonGroupRichContent, disabled-selected demos), and unit tests cover loading/disabled selection behavior.Reviewed by Cursor Bugbot for commit 28deeac. Bugbot is set up for automated code reviews on this repo. Configure here.