Skip to content

RadioGroup can no longer be used as a controlled component when there is no initial value #3844

@jonaldinger

Description

@jonaldinger

What package within Headless UI are you using?

@headlessui/react

What version of that package are you using?

v2.2.9

What browser are you using?

Chrome

Reproduction URL

https://codesandbox.io/p/devbox/np6ywm

Describe your issue

When using RadioGroup under the following conditions:

  1. As a controlled component
  2. With no default selection/value

(The use case here is a survey with a multiple choice question, where the user must make an explicit choice for compliance reasons - no default selection is permitted)

Then:

The component switches from uncontrolled to controlled, and I receive the following warning in the console: "A component is changing from uncontrolled to controlled. This may be caused by the value changing from undefined to a defined value, which should not happen."

Beyond the warning, this does cause actual buggy behavior in my app, as expected when going from uncontrolled to controlled (so thank you for emitting the console warning!)

Previous solution:

In Headless UI v2.2.7, I passed an explicit null value when no selection had been made:

<RadioGroup value={selected ?? null} />

This solved my issue, because the value would then change from null -> string, avoiding the explicit logic around undefined in use-controllable.ts:

let isControlled = controlledValue !== undefined

Bug:

In Headless UI v2.2.9, I receive the following TypeError when passing a value of null:

Type 'NonNullable<T> | null' is not assignable to type 'T | undefined'.
  Type 'null' is not assignable to type 'T | undefined'.ts(2322)

radio-group.d.ts(13, 5): The expected type comes from property 'value' which is declared here on type 'IntrinsicAttributes & CleanProps<"div", "onChange" | "value" | "form" | "disabled" | "name" | "by" | "defaultValue" | RadioGroupPropsWeControl> & OurProps<...> & { ...; } & { ...; } & { ...; }'

So now it does not seem possible to satisfy my use case without hacks. This was a patch-level version upgrade so I was not expecting functionality to be impacted, and I don't see anything in the changelog about the typings changing. This use case does not seem like an edge case, so I'm wondering if there's anything I'm overlooking?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions