headlessui icon indicating copy to clipboard operation
headlessui copied to clipboard

"Invalid prop `data-headlessui-state` supplied to `React.Fragment`. React.Fragment can only have `key` and `children` props."

Open tordans opened this issue 1 year ago • 19 comments

What package within Headless UI are you using?

"@headlessui/react": "0.0.0-insiders.fbad6a9",

What browser are you using?

For example: Chrome

Reproduction URL

I was not able to create a minimal reproduction, yet. Will update once I have one. Wanted to share the issue now so others can search for it and help.

Describe your issue

I am testing React 19, Next 15, React Compiler in our Project. When rendering our app I am getting multiple console errors in the browser like…

Warning: Invalid prop `data-headlessui-state` supplied to `React.Fragment`. React.Fragment can only have `key` and `children` props.
    at c (webpack-internal:///(app-pages-browser)/./node_modules/@headlessui/react/dist/internal/open-closed.js:17:18)
    at u (webpack-internal:///(app-pages-browser)/./node_modules/@headlessui/react/dist/internal/close-provider.js:13:18)
    at me (webpack-internal:///(app-pages-browser)/./node_modules/@headlessui/react/dist/components/disclosure/disclosure.js:111:24)
    at SelectDatasets (webpack-internal:///(app-pages-browser)/./src/app/regionen/[regionSlug]/_components/SidebarLayerControls/StaticDatasets/SelectDatasets.tsx:32:72)
    at nav
    …

I am seeing the same error with other libraries, so this might be a temporary or a new issue with React 19 or Next 15 or React Compiler.

tordans avatar Jul 01 '24 10:07 tordans

Hmm interesting, I'm assuming you are using Headless UI in SelectDatasets. Do you have access to the generated output that the compiler outputs for this file?

RobinMalfait avatar Jul 01 '24 11:07 RobinMalfait

I'm assuming you are using Headless UI in SelectDatasets.

Yes, this case is from https://github.com/FixMyBerlin/atlas-app/blob/react-compiler-react-19/src/app/regionen/%5BregionSlug%5D/_components/SidebarLayerControls/StaticDatasets/SelectDatasets.tsx#L1-L8 and starts in the Disclosure. However there are quite a few similar warnings from other components.

Do you have access to the generated output that the compiler outputs for this file?

I am seeing this value 2 on which I assume is the Fragment u: image

Any recommendation how to extract the relevant code?

tordans avatar Jul 01 '24 11:07 tordans

I have the same problem. It only occurs only in development mode.

kuskhan avatar Jul 24 '24 00:07 kuskhan

same issue testing React 19 rc.. waiting for updates!

agusabas avatar Aug 12 '24 14:08 agusabas

Same issue happening in React 19 RC

Solution that worked for me is to add the as="div" prop to the <Disclosure /> component like this: <Disclosure {...rest} as="div">

6ichem avatar Oct 29 '24 07:10 6ichem

Same issue happening in React 19 RC

Solution that worked for me is to add the as="div" prop to the <Disclosure /> component like this: <Disclosure {...rest} as="div">

don't work for me

yuriiIykyknow avatar Nov 21 '24 20:11 yuriiIykyknow

This is happening to me in "react": 18.3.1 not 19.. just wanted to share. And we're not using the Disclosure component.

dwilt avatar Nov 26 '24 13:11 dwilt

Thanks @6ichem 
this worked for me as well by adding the as="div" prop to the Disclosure wrapper component.
Wanted to add, that on React 18.2

michaelkhalsa avatar Nov 29 '24 03:11 michaelkhalsa

This error is very annoying........ I hope it gets fixed soon. Using NextJS 15 and React 18. This is not workable.

DaanBiesterbos avatar Jan 10 '25 01:01 DaanBiesterbos

Happening in React 19 with Vite 6, happening in Listbox. Using as="div" resolved the issue, but Idk whether there's any side effect

xsjcTony avatar Jan 13 '25 04:01 xsjcTony

Happening with React 19 and Next 15.1.6 when using Menu. Using as="div" resolved the issue. Any updates if this gets fixed?

mblazek-moravio avatar Feb 04 '25 09:02 mblazek-moravio

Hey!

Can anyone running into this issue provide a minimal reproduction repo? Inside of Headless UI we check whether a Fragment was used or not. Only thing I can think of is that there is a different instance of Fragment, but looking at the React Compiler it seems like they just use Fragment from the react package directly.

Would love to get it fixed, so if anyone can share a reproduction that will be greatly appreciated.

RobinMalfait avatar Feb 13 '25 11:02 RobinMalfait

Got it: https://stackblitz.com/edit/vitejs-vite-x9bjfwzm?file=src%2Fmain.tsx

I simplified it down from this file.

import { createRoot } from 'react-dom/client';
import {
  Listbox,
  ListboxButton,
  ListboxOption,
  ListboxOptions,
} from '@headlessui/react';

createRoot(document.getElementById('root')!).render(
  <Listbox>
    {/* this fragment is the problem! */}
    <>
      <ListboxButton>Select an option</ListboxButton>
      <ListboxOptions>
        <ListboxOption value="hi">Hello</ListboxOption>
        <ListboxOption value="v2">Another</ListboxOption>
      </ListboxOptions>
    </>
  </Listbox>
);

The fragment here in minimal form is pointless, but in practice the point is to do this:

<Listbox>
  {({ open }) => (
    <>
      {/* label + button + options depend on open, etc. */}
    </>
  )}
</Listbox>
Image

david-crespo avatar Feb 17 '25 22:02 david-crespo

This can be mitigated by replacing the fragment with <div> with display: contents style

alekseikurnosenko avatar Apr 16 '25 07:04 alekseikurnosenko

I'm not a user of this repo, but I have a similar problem with react-native:

Warning: Invalid prop onLayout supplied to React.Fragment.

I filed the issue 50817 at https://github.com/facebook/react-native.

What looks similar to me is in: headlessui/packages/@headlessui-react/src/utils/render.ts

    if (exposeState) {
      dataAttributes['data-headlessui-state'] = states.join(' ')    <-- HERE
...
        return cloneElement(
          resolvedChildren,    <-- HERE, is probably the Fragment
          Object.assign(
            {},
            mergedProps,
            dataAttributes,    <-- HERE, prop addition
...

I don't see the relation with the packages/react-native/Libraries/Renderer/implementations/ReactFabric-dev.js of my case (is Fabric an engine library used in both products?).

psam44 avatar Apr 20 '25 13:04 psam44

@psam44 your issue is related only in that something you’re doing or a library you’re using is violating the same prohibition as this one. The prohibition comes from React itself. You can reproduce this with plain React without any libraries by making a fragment and passing props other than key and children to it. Fabric is part of React Native: https://reactnative.dev/architecture/fabric-renderer

david-crespo avatar Apr 20 '25 14:04 david-crespo

If you look closely at my comment in 50817, I know who is the producer of the 'onLayout' prop. But I located the exact error message in the Fabric renderer (so before React, I suppose). May be there is the same checker in React, but I didn't spot something like that in the source repo (and I don't really know where to search for). If you know where the check is in React, I'm interested.

-- edit For what it worths, with this temporary hack in /node_modules/react-native/Libraries\Renderer/implementations/ReactFabric-dev.js, there is no more error/warning:

//        if ("children" !== key && "key" !== key) {
        if ("children" !== key && "key" !== key && "onLayout" !== key && "style" !== key) {

So I still don't know where would React raise a message.

psam44 avatar Apr 20 '25 14:04 psam44

Finally found in https://github.com/facebook/react/blob/main/packages/react-reconciler/src/ReactChildFiber.js

function validateFragmentProps(
...
      if (
        key !== 'children' &&
        key !== 'key' &&
        (enableFragmentRefs ? key !== 'ref' : true)
      ) {
...
            if (enableFragmentRefs) {
              console.error(
                'Invalid prop `%s` supplied to `React.Fragment`. ' +
                  'React.Fragment can only have `key`, `ref`, and `children` props.',
                erroredKey,
              );
            } else {
              console.error(
                'Invalid prop `%s` supplied to `React.Fragment`. ' +
                  'React.Fragment can only have `key` and `children` props.',
                erroredKey,
              );
            }
...

This file is present in v19.0.0, not in v18.3.1.

psam44 avatar Apr 20 '25 15:04 psam44

My issue for react-native has now a fix committed. And the decision is to inhibit the producer to provide additional props when the child is a Fragment. Extract:

    const isFragment = element.type === React.Fragment;
    if (isFragment) {
      return element;
    }
    return React.cloneElement(element, {
      onLayout: (event: LayoutChangeEvent) => {
...

So for your ListBox, I suppose you have to choose: either accept to not support a Fragment as a child, either do not pass any additional attribute (i.e. return resolvedChildren as is).

psam44 avatar Apr 22 '25 17:04 psam44

Same issue happening in React 19 RC

Solution that worked for me is to add the as="div" prop to the <Disclosure /> component like this: <Disclosure {...rest} as="div">

Thank you. It solved!

ikramhasib007 avatar Jul 11 '25 17:07 ikramhasib007

For some reason, I only encountered the same issue when using the experimental.browserDebugInfoInTerminal feature from Next.js. There was no issue when I toggled it off, and it only appeared on my terminal.

<Disclosure>
  {({ open }) => (
    <>
      <DisclosureButton className="flex items-center gap-2">
        Do you offer technical support?
        <ChevronDownIcon className={clsx('w-5', open && 'rotate-180')} />
      </DisclosureButton>
      <DisclosurePanel>No</DisclosurePanel>
    </>
  )}
</Disclosure>

JeromeDeLeon avatar Aug 02 '25 09:08 JeromeDeLeon

This should be fixed by #3788, and will be available in the next release.

You can already try it using:

  • npm install @headlessui/react@insiders.

RobinMalfait avatar Sep 10 '25 10:09 RobinMalfait