Next.js Discord

Discord Forum

Error about controlled input

Answered
American Chinchilla posted this in #help-forum
Open in Discord
American ChinchillaOP
Warning: A component is changing a controlled input to be uncontrolled. This is likely caused by the value changing from a defined to undefined, which should not happen. Decide between using a controlled or uncontrolled input element for the lifetime of the component. More info: https://reactjs.org/link/controlled-components
error i get ^
i dont really understand what it is wrong with my code based on the link they provided the problem im facing is that the radio button is not selected as Firma on startup (i tried adding checked={clientType === "Osoba Fizyczna"} etc but then it didnt show even when i clicked on it)
basically i have those 2 RadioButtons
  type ClientType = "Osoba fizyczna" | "Firma";
  const [clientType, setClientType] = useState<ClientType>("Firma");

  const handleClientTypeChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    setClientType(e.target.value as ClientType);
  };
<RadioButton
                name="client-type"
                label="Osoba fizyczna"
                value="Osoba fizyczna"
                onChange={handleClientTypeChange}
              />
              <RadioButton
                name="client-type"
                label="Firma"
                value="Firma"
                onChange={handleClientTypeChange}
              />
and it decides about visibility of div below
<div
              className={cn(
                "flex flex-col items-start gap-4 w-full 1144:flex-row",
                clientType === "Osoba fizyczna" && "hidden"
              )}
            >
...
</div>
Answered by joulev
controlled radio groups are structured quite differently from normal text inputs. basically you need to provide the checked prop. see here for a basic example:

"use client";

import { useState } from "react";

function RadioButton({
  name,
  option,
  selected,
  onSelect,
  children,
}: {
  name: string;
  option: string;
  selected: boolean;
  onSelect: () => void;
  children: React.ReactNode;
}) {
  return (
    <label>
      <input
        type="radio"
        name={name}
        value={option}
        checked={selected}
        onChange={e => e.target.checked && onSelect()}
        className="h-4 w-4"
      />
      <span>{children}</span>
    </label>
  );
}

function RadioGroup({
  name,
  value,
  setValue,
  options,
}: {
  name: string;
  value: string;
  setValue: (value: string) => void;
  options: string[];
}) {
  return options.map(option => (
    <RadioButton
      key={option}
      name={name}
      option={option}
      selected={value === option}
      onSelect={() => setValue(option)}
    >
      {option}
    </RadioButton>
  ));
}

export default function Page() {
  const [value, setValue] = useState("option1");
  return (
    <div>
      <div>Selected value: {value}</div>
      <RadioGroup
        name="group1"
        value={value}
        setValue={setValue}
        options={["option1", "option2", "option3"]}
      />
    </div>
  );
}
View full answer

3 Replies

American ChinchillaOP
also this is RadioButton component
"use client";

import { RadioButtonProps } from "@/interfaces/RadioButton";

const RadioButton = ({ label, ...props }: RadioButtonProps) => {
  return (
    <label className="flex items-center gap-3">
      <input type="radio" {...props} />
      <span className="body2-400 text-typography-200 hover:text-typography-100 focus:text-typography-100 disabled:text-gray-300">
        {label}
      </span>
    </label>
  );
};

export default RadioButton;
@American Chinchilla Warning: A component is changing a controlled input to be uncontrolled. This is likely caused by the value changing from a defined to undefined, which should not happen. Decide between using a controlled or uncontrolled input element for the lifetime of the component. More info: https://reactjs.org/link/controlled-components error i get ^ i dont really understand what it is wrong with my code based on the link they provided the problem im facing is that the radio button is not selected as `Firma` on startup (i tried adding checked={clientType === "Osoba Fizyczna"} etc but then it didnt show even when i clicked on it) basically i have those 2 RadioButtons tsx type ClientType = "Osoba fizyczna" | "Firma"; const [clientType, setClientType] = useState<ClientType>("Firma"); const handleClientTypeChange = (e: React.ChangeEvent<HTMLInputElement>) => { setClientType(e.target.value as ClientType); }; <RadioButton name="client-type" label="Osoba fizyczna" value="Osoba fizyczna" onChange={handleClientTypeChange} /> <RadioButton name="client-type" label="Firma" value="Firma" onChange={handleClientTypeChange} /> and it decides about visibility of div below tsx <div className={cn( "flex flex-col items-start gap-4 w-full 1144:flex-row", clientType === "Osoba fizyczna" && "hidden" )} > ... </div>
controlled radio groups are structured quite differently from normal text inputs. basically you need to provide the checked prop. see here for a basic example:

"use client";

import { useState } from "react";

function RadioButton({
  name,
  option,
  selected,
  onSelect,
  children,
}: {
  name: string;
  option: string;
  selected: boolean;
  onSelect: () => void;
  children: React.ReactNode;
}) {
  return (
    <label>
      <input
        type="radio"
        name={name}
        value={option}
        checked={selected}
        onChange={e => e.target.checked && onSelect()}
        className="h-4 w-4"
      />
      <span>{children}</span>
    </label>
  );
}

function RadioGroup({
  name,
  value,
  setValue,
  options,
}: {
  name: string;
  value: string;
  setValue: (value: string) => void;
  options: string[];
}) {
  return options.map(option => (
    <RadioButton
      key={option}
      name={name}
      option={option}
      selected={value === option}
      onSelect={() => setValue(option)}
    >
      {option}
    </RadioButton>
  ));
}

export default function Page() {
  const [value, setValue] = useState("option1");
  return (
    <div>
      <div>Selected value: {value}</div>
      <RadioGroup
        name="group1"
        value={value}
        setValue={setValue}
        options={["option1", "option2", "option3"]}
      />
    </div>
  );
}
Answer
American ChinchillaOP
oh okay thanks