Repository: tailwindlabs/headlessui
Pull request #2941 (2024-01-23 12:58:01)

Ensure `children` prop of `Field` component can be a render prop
This PR ensures that the `Field` can be used using a render prop as the children of the `Field` component.

This means that we can now do this again:

```tsx
<Field>
  {({ disabled }) => {
    return <input className={disabled ? "..." : "..."} />;
  }}
</Field>
```

This normally works in every component, but it was missing because we were manually wrapping the children in a component and forgot to handle this case.



Patch:
diff --git a/packages/@headlessui-react/CHANGELOG.md b/packages/@headlessui-react/CHANGELOG.md
index f98abbf..52d371a 100644
--- a/packages/@headlessui-react/CHANGELOG.md
+++ b/packages/@headlessui-react/CHANGELOG.md
@@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 - Expose `disabled` state on `<Tab />` component ([#2918](https://github.com/tailwindlabs/headlessui/pull/2918))
 - Prevent default behaviour when clicking outside of a `Dialog.Panel` ([#2919](https://github.com/tailwindlabs/headlessui/pull/2919))
 - Use `isFocused` instead of `isFocusVisible` for `Input` and `Textarea` components ([#2940](https://github.com/tailwindlabs/headlessui/pull/2940))
+- Ensure `children` prop of `Field` component can be a render prop ([#2941](https://github.com/tailwindlabs/headlessui/pull/2941))
 
 ## [2.0.0-alpha.4] - 2024-01-03
 
diff --git a/packages/@headlessui-react/src/components/field/field.tsx b/packages/@headlessui-react/src/components/field/field.tsx
index 0a22218..d770c16 100644
--- a/packages/@headlessui-react/src/components/field/field.tsx
+++ b/packages/@headlessui-react/src/components/field/field.tsx
@@ -53,7 +53,13 @@ function FieldFn<TTag extends ElementType = typeof DEFAULT_FIELD_TAG>(
               ourProps,
               theirProps: {
                 ...theirProps,
-                children: <FormFieldsProvider>{theirProps.children}</FormFieldsProvider>,
+                children: (
+                  <FormFieldsProvider>
+                    {typeof theirProps.children === 'function'
+                      ? theirProps.children(slot)
+                      : theirProps.children}
+                  </FormFieldsProvider>
+                ),
               },
               slot,
               defaultTag: DEFAULT_FIELD_TAG,


Test patch:
diff --git a/packages/@headlessui-react/src/components/field/field.test.tsx b/packages/@headlessui-react/src/components/field/field.test.tsx
index 0ec7dd2..d1c8b88 100644
--- a/packages/@headlessui-react/src/components/field/field.test.tsx
+++ b/packages/@headlessui-react/src/components/field/field.test.tsx
@@ -14,6 +14,25 @@ describe('Rendering', () => {
     expect(container.firstChild).not.toHaveAttribute('aria-disabled', 'true')
   })
 
+  it('should render a `Field` component with a render prop', async () => {
+    let { container } = render(
+      <Field>
+        {(slot) => {
+          return (
+            <div data-slot={JSON.stringify(slot)}>
+              <input />
+            </div>
+          )
+        }}
+      </Field>
+    )
+
+    expect(container.querySelector('[data-slot]')?.getAttribute('data-slot')).toEqual(
+      JSON.stringify({ disabled: false })
+    )
+    expect(container.firstChild).not.toHaveAttribute('aria-disabled', 'true')
+  })
+
   it('should add `aria-disabled` when a `Field` is disabled', async () => {
     let { container } = render(
       <Field disabled>