Skip to main content

RadioGroup / Checkbox disabled label via :has()

Version: 0.2.0 ยท Type: ๐Ÿ› Bug Fix

Problemโ€‹

When label is passed to RadioGroupItem / Checkbox, the disabled state only grayed out the control itself (the circle / box), while the label text stayed normal black and the cursor was not not-allowed, making the visuals inconsistent.

There were two layers to the root cause:

  1. The label row container only declared data-disabled:cursor-not-allowed, with no disabled-state text color.
  2. More importantly: the label's disabled state originally relied on the data-disabled that the component manually set on <label> (sourced from the item's own disabled prop). But when disabled is set at the RadioGroup group level, an individual item does not receive that prop, so <label> carries no data-disabled, and the entire data-disabled:* rule set fails to match โ€” neither the cursor nor the text color take effect. Radix, meanwhile, still sets data-disabled on the internal radio button.

Changed Filesโ€‹

  • packages/design/src/components/RadioGroup/styles.ts
  • packages/design/src/components/Checkbox/styles.ts
  • packages/design/src/components/RadioGroup/RadioGroup.test.tsx
  • packages/design/src/components/Checkbox/Checkbox.test.tsx

Changesโ€‹

  • The disabled state of RADIO_LABEL_CLASS / CHECKBOX_LABEL_CLASS is changed to be driven by :has([data-disabled]): has-[[data-disabled]]:cursor-not-allowed + has-[[data-disabled]]:text-(--Labels-Disabled). Since Radix sets data-disabled on the internal control for both item-level and group-level disabling, the whole-row disabled state is inferred from that, so both disable sources correctly gray out (text degrades to Labels/Disabled #A3A3A3).
  • Consistent with the disabled-text convention of components like Button (unified --Labels-Disabled).
  • Both components keep the manual data-disabled on <label> (item-level semantic marker), but the styling no longer depends on it.
  • Tests: assert the label carries the has-[[data-disabled]]:* classes and the internal control carries data-disabled; RadioGroup adds a group-level disabled case (an item without a disabled prop can still be inferred).

Notesโ€‹