reactjsformsnext.jsradio-button

React 19 Radio button bug - appears unchecked after form submission even though controlled state is checked


I have a weird issue with radio inputs. I have form in Next 15 (React 19) with a controlled state. The problem I'm having is that when I submit my form, the checked radio input is suddenly appearing unchecked. But the React state shows it still as being checked.

I have seen that with React 19 forms are auto cleared when submitted, so I changed from an uncontrolled state to a controlled one. As I don't want to clear my form if the action returns any validation errors. This works as I'd expect for text inputs.

Steps:

  1. Check Radio 1
  2. Hit submit button
  3. Action returns state with errors
  4. Radio 1 appears unchecked in render
  5. console.log still shows formValues.searchType = 1
  6. conditional section 1 still appears rendered
"use client"

...

const defaultState = {
    errors: [],
    fieldValues: {
        searchType: "",
    }
};


export default function SomeForm() {
    const [actionState, formAction, isPending] = useActionState(importedAction, defaultState);
    const [formValues, setFormValues] = useState(defaultState.fieldValues);

    console.log(formValues.searchType);

    const handleRadioOption = (e: ChangeEvent<HTMLInputElement>) => {
        setFormValues({
            ...defaultState.fieldValues, 
            searchType: e.currentTarget.value
        });
    }

return (
    <Form action={formAction}>
        <fieldset>
            <legend>Select an option</legend>
            <input
                type="radio"
                id="option1-radio"
                label="Search by 1"
                aria-controls="conditional-1"
                name="searchType"
                value="1"
                onChange={handleRadioOption}
                checked={formValues.searchType === "1"}
            />
            {formValues.searchType === "1" && <div id="conditional-1">conditional section 1</div>}
            <input
                type="radio"
                id="option2-radio"
                label="Search by 2"
                aria-controls="conditional-2"
                name="searchType"
                value="2"
                onChange={handleRadioOption}
                checked={formValues.searchType === "2"}
            />
            {formValues.searchType === "2" && <div id="conditional-2">conditional section 2 </div>}
        </fieldset>

        <button disabled={isPending}>Continue</Button>
    </Form>
);


}

I expect the radio input to render as checked or unchecked based on the checked prop, but it is always appearing unchecked after submitting the form.

I have tried using uncontrolled state with defaultValue, but I need to also control the rendering of a conditional section, so that's not an option.

I have tried a normal <form/> element as well as the Next <Form/> but both have this issue

Added a codesandbox here showing the issue: https://codesandbox.io/p/devbox/cocky-shannon-forked-8qlwzy?file=%2Fapp%2Fform%2Fcomponent.tsx%3A11%2C15&workspaceId=ws_YJunuyU6avBk8pMTbNjaGv


Solution

  • This is a bug with the latest version of React 19. There is an issue raised here: https://github.com/facebook/react/issues/31695

    I have a workaround, which is to add a onSubmit handler to the form, prevent the default behaviour, and manually call the action inside startTransition.

        const handleSubmit = async (e: FormEvent<HTMLFormElement>) => {
            e.preventDefault();
            const formData = new FormData(formRef.current);
    
            startTransition(() => {
                formAction(formData);
            });
        };