primitives icon indicating copy to clipboard operation
primitives copied to clipboard

Checkbox resets its INTERNAL state in the form and delivers none to FormData after a button with formAction is clicked

Open dimikot opened this issue 8 months ago • 1 comments

Bug report

Suppose we have a form with 1 checkbox and 1 button, and that button has a formAction handler. When clicking the button, the handler is fed with a FormData object. If we select the checkbox, the 1st click to the button delivers its state in that FormData.

But if we click the button the 2nd time, FormData is delivered empty. The same happens in onSubmit handler of the <form> itself. This is all despite the checkbox itself is still visually on.

This happens, because formAction on a button resets the form. So it implicitly resets all of the checkboxes in the form to their default state. But visually, nothing changes, since rendering of the Checkbox state is independent on the actual <input type="checkbox"/> state. There is a huge thread about resetting the form on formData in React repo: https://github.com/facebook/react/issues/29034 - but anyways, since radix-ui hides the actual <input/> element, this all becomes counter-intuitive.

Current Behavior

https://github.com/user-attachments/assets/0b2027e9-d7ad-4906-853e-48c48a93daaf

Image

Image

Expected behavior

After clicking the button the 2nd time, FormData should still contain that checkbox. But for some reason, the checked property of the invisible <input> element gets reset (without re-rendering).

Reproducible example

"use client";

import { Button } from "@/components/ui/button.tsx";
import { Checkbox } from "@/components/ui/checkbox.tsx";
import { useState } from "react";

export default function Page() {
  const [checked, setChecked] = useState(false);
  console.log("Rendered as:", checked);
  return (
    <form className="m-10 flex flex-row items-center gap-2">
      <Checkbox
        name="checkbox"
        value="42"
        checked={checked}
        onClick={() => setChecked(!checked)}
      />
      <Button
        type="submit"
        formAction={(formData) => console.log(formData.getAll("checkbox"))}
      >
        Submit
      </Button>
    </form>
  );
}

Your environment

Software Name(s) Version
Radix Package(s) @radix-ui/react-checkbox 1.1.4
React ^19.0.0
Browser Chrome
Assistive tech
Node n/a
npm/yarn
Operating System

dimikot avatar Apr 04 '25 23:04 dimikot

I just ran into this, using the checkbox with function actions. The React docs at https://react.dev/reference/react-dom/components/form#handle-form-submission-on-the-client mention:

After the action function succeeds, all uncontrolled field elements in the form are reset.

It seems the hidden inputs attached to these checkboxes are reset in an unexpected way. This creates some weird bugs, especially with checkbox groups, and I'm not sure the best way to fix this without resorting to hacks.

There must be some workaround? Or do people not really use these components with form actions in React 19?

chipit24 avatar Jun 13 '25 02:06 chipit24