Repository: tailwindlabs/headlessui
Pull request #3095 (2024-04-11 15:28:28)

Render hidden form input fields for `Checkbox`, `Switch` and `RadioGroup` components
This PR ensures that we always render the hidden form input elements for the `Checkbox`, `Switch` and `RadioGroup` components.

The reason why we didn't render them was because they weren't included in the `FormData` anyway as long as they are not "checked". However, this makes it harder if you want to get access to the elements if you use some form library that uses the inputs in the form. Additionally, this also means that we were adding and removing elements from the DOM.

Now with this change, they will always be there and the `checked` attribute will be updated behind the scenes instead. Now, the hidden inputs will always be available in the form data.

Note: if you don't pass the `name` prop, the hidden form inputs won't be rendered (same behavior as before).

Fixes: #2977


vercel[bot]: [vc]: #i32swvuOhRpzRtM24nzfMx6Sv7wgeonLxlgapc9wtlg=:eyJpc01vbm9yZXBvIjp0cnVlLCJ0eXBlIjoiZ2l0aHViIiwicHJvamVjdHMiOlt7Im5hbWUiOiJoZWFkbGVzc3VpLXJlYWN0Iiwicm9vdERpcmVjdG9yeSI6InBsYXlncm91bmRzL3JlYWN0IiwiaW5zcGVjdG9yVXJsIjoiaHR0cHM6Ly92ZXJjZWwuY29tL3RhaWx3aW5kbGFicy9oZWFkbGVzc3VpLXJlYWN0LzZ6M1pVczNnbnZ6MjIxc3JGUE1CVEU4UUZNYkMiLCJwcmV2aWV3VXJsIjoiaGVhZGxlc3N1aS1yZWFjdC1naXQtZml4LWlzc3VlLTI5NzctdGFpbHdpbmRsYWJzLnZlcmNlbC5hcHAiLCJuZXh0Q29tbWl0U3RhdHVzIjoiUEVORElORyIsImxpdmVGZWVkYmFjayI6eyJyZXNvbHZlZCI6MCwidW5yZXNvbHZlZCI6MCwidG90YWwiOjAsImxpbmsiOiJoZWFkbGVzc3VpLXJlYWN0LWdpdC1maXgtaXNzdWUtMjk3Ny10YWlsd2luZGxhYnMudmVyY2VsLmFwcCJ9fV19
**The latest updates on your projects**. Learn more about [Vercel for Git ↗︎](https://vercel.link/github-learn-more)

| Name | Status | Preview | Comments | Updated (UTC) |
| :--- | :----- | :------ | :------- | :------ |
| **headlessui-react** | 🔄 Building ([Inspect](https://vercel.com/tailwindlabs/headlessui-react/6z3ZUs3gnvz221srFPMBTE8QFMbC)) | [Visit Preview](https://vercel.live/open-feedback/headlessui-react-git-fix-issue-2977-tailwindlabs.vercel.app?via=pr-comment-visit-preview-link&passThrough=1) | 💬 [**Add feedback**](https://vercel.live/open-feedback/headlessui-react-git-fix-issue-2977-tailwindlabs.vercel.app?via=pr-comment-feedback-link) | Apr 11, 2024 3:28pm |



Patch:
diff --git a/packages/@headlessui-react/CHANGELOG.md b/packages/@headlessui-react/CHANGELOG.md
index 6c9ecf2..3694842 100644
--- a/packages/@headlessui-react/CHANGELOG.md
+++ b/packages/@headlessui-react/CHANGELOG.md
@@ -24,6 +24,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 - Fix cursor position when re-focusing the `ComboboxInput` component ([#3065](https://github.com/tailwindlabs/headlessui/pull/3065))
 - Keep focus inside of the `<ComboboxInput />` component ([#3073](https://github.com/tailwindlabs/headlessui/pull/3073))
 - Fix enter transitions for the `Transition` component ([#3074](https://github.com/tailwindlabs/headlessui/pull/3074))
+- Render hidden form input fields for `Checkbox`, `Switch` and `RadioGroup` components ([#3095](https://github.com/tailwindlabs/headlessui/pull/3095))
 
 ### Changed
 
diff --git a/packages/@headlessui-react/src/components/checkbox/checkbox.tsx b/packages/@headlessui-react/src/components/checkbox/checkbox.tsx
index 1c179ec..a8d743a 100644
--- a/packages/@headlessui-react/src/components/checkbox/checkbox.tsx
+++ b/packages/@headlessui-react/src/components/checkbox/checkbox.tsx
@@ -174,7 +174,8 @@ function CheckboxFn<TTag extends ElementType = typeof DEFAULT_CHECKBOX_TAG, TTyp
       {name != null && (
         <FormFields
           disabled={disabled}
-          data={checked ? { [name]: value || 'on' } : {}}
+          data={{ [name]: value || 'on' }}
+          overrides={{ type: 'checkbox', checked }}
           form={form}
           onReset={reset}
         />
diff --git a/packages/@headlessui-react/src/components/radio-group/radio-group.tsx b/packages/@headlessui-react/src/components/radio-group/radio-group.tsx
index 93fce6f..3585106 100644
--- a/packages/@headlessui-react/src/components/radio-group/radio-group.tsx
+++ b/packages/@headlessui-react/src/components/radio-group/radio-group.tsx
@@ -315,7 +315,8 @@ function RadioGroupFn<TTag extends ElementType = typeof DEFAULT_RADIO_GROUP_TAG,
             {name != null && (
               <FormFields
                 disabled={disabled}
-                data={value != null ? { [name]: value || 'on' } : {}}
+                data={{ [name]: value || 'on' }}
+                overrides={{ type: 'radio', checked: value != null }}
                 form={form}
                 onReset={reset}
               />
diff --git a/packages/@headlessui-react/src/components/switch/switch.tsx b/packages/@headlessui-react/src/components/switch/switch.tsx
index 56b6c7b..45cc4a3 100644
--- a/packages/@headlessui-react/src/components/switch/switch.tsx
+++ b/packages/@headlessui-react/src/components/switch/switch.tsx
@@ -240,7 +240,8 @@ function SwitchFn<TTag extends ElementType = typeof DEFAULT_SWITCH_TAG>(
       {name != null && (
         <FormFields
           disabled={disabled}
-          data={checked ? { [name]: value || 'on' } : {}}
+          data={{ [name]: value || 'on' }}
+          overrides={{ type: 'checkbox', checked }}
           form={form}
           onReset={reset}
         />
diff --git a/packages/@headlessui-react/src/internal/form-fields.tsx b/packages/@headlessui-react/src/internal/form-fields.tsx
index ab94d98..d0d960c 100644
--- a/packages/@headlessui-react/src/internal/form-fields.tsx
+++ b/packages/@headlessui-react/src/internal/form-fields.tsx
@@ -33,8 +33,10 @@ export function FormFields({
   form: formId,
   disabled,
   onReset,
+  overrides,
 }: {
   data: Record<string, any>
+  overrides?: Record<string, any>
   form?: string
   disabled?: boolean
   onReset?: (e: Event) => void
@@ -66,6 +68,7 @@ export function FormFields({
               disabled,
               name,
               value,
+              ...overrides,
             })}
           />
         )


Test patch:
diff --git a/packages/@headlessui-react/src/components/checkbox/checkbox.test.tsx b/packages/@headlessui-react/src/components/checkbox/checkbox.test.tsx
index 623fcdb..4aff676 100644
--- a/packages/@headlessui-react/src/components/checkbox/checkbox.test.tsx
+++ b/packages/@headlessui-react/src/components/checkbox/checkbox.test.tsx
@@ -135,8 +135,10 @@ describe('Form submissions', () => {
       </form>
     )
 
+    let checkbox = document.querySelector('[id^="headlessui-checkbox-"]') as HTMLInputElement
+
     // Focus the checkbox
-    await focus(getCheckbox())
+    await focus(checkbox)
 
     // Submit
     await press(Keys.Enter)
@@ -145,7 +147,7 @@ describe('Form submissions', () => {
     expect(handleSubmission).toHaveBeenLastCalledWith({})
 
     // Toggle
-    await click(getCheckbox())
+    await click(checkbox)
 
     // Submit
     await press(Keys.Enter)
@@ -154,7 +156,7 @@ describe('Form submissions', () => {
     expect(handleSubmission).toHaveBeenLastCalledWith({ notifications: 'on' })
 
     // Toggle
-    await click(getCheckbox())
+    await click(checkbox)
 
     // Submit
     await press(Keys.Enter)