radix-ui / primitives

Radix Primitives is an open-source UI component library for building high-quality, accessible design systems and web apps. Maintained by @workos.
https://radix-ui.com/primitives
MIT License
15.62k stars 800 forks source link

How can I read component internal state #2904

Closed michaltaberski closed 4 months ago

michaltaberski commented 5 months ago

Hi,

I wonder what's the desired pattern to read the internal state of the primitives. It's possible to style components conditionally because of the state is exposed to DOM through data-attributes.

That's cool, but what is the pattern for following scenario:

Preconditions

1) Build radio cards 2) Option can have different look for "checked" and "unchecked" state. eg:

// not a real example but it represents the idea
options = [{ selectedLabel: 'Select me', unselectedLabel: 'I am not selected' }]

I would look for something to be able to do:

const isSelected = // how to get this value?
return <>{isSelected ? option.selectedLabel : option.unselectedLabel}</>

So far I couldn't find a better approach than a hack component:

const RenderProps = forwardRef(({ children, ...props }, ref) => {
  return children({ ...props, ref });
});

// usage
<RadixRadioGroup.Item value={value} asChild>
  <RenderProps>
    {({ 'aria-checked': isSelected }) => (
      <>{isSelected ? option.selectedLabel : option.unselectedLabel}</>
    )}
  </RenderProps>
<RadixRadioGroup.Item/>

However this is obvious hack - surly I am not getting something from the library philosophy.

joaom00 commented 4 months ago

you can use the parent's data attribute to style the child via css only. as I usually use tailwind I would use the group modifier

vladmoroz commented 4 months ago

You can't "read" the internal state of the components, but you can create your own controlled components and use that state as the source of truth. In the case of radio group items, you'd also need to pass down the current value from root to the items via React context.

For example, see the Segmented Control component in Radix Themes which is built on top of the Toggle Group primitive. Instead of "reading" the primitive state, it bases its state on the value props and passes them down to the primitive.

https://github.com/radix-ui/themes/blob/616a66fb37d8d92e8ee5b02abf798ab405ae247e/packages/radix-ui-themes/src/components/segmented-control.tsx