tailwindlabs / headlessui

Completely unstyled, fully accessible UI components, designed to integrate beautifully with Tailwind CSS.
https://headlessui.com
MIT License
25.02k stars 1.03k forks source link

New `transition` property in 2.1 shadows `transition` property from framer motion when using `as` on `ComboboxOptions` #3333

Closed augustl closed 1 day ago

augustl commented 5 days ago

What package within Headless UI are you using?

@headlessui/react

What version of that package are you using?

2.1.1

What browser are you using?

Firefox

Describe your issue

This code worked in Headlessui 2.0:

<ComboboxOptions
    as={motion.div}
    transition={{ease: "linear", duration: 2}}
    initial={{ y: -20, opacity: 0 }}
    animate={{ y: 0, opacity: 1 }}
    exit={{ y: -20, opacity: 0 }}
>

But in Headlessui 2.1, it causes a typescript compile error (it only accepts a boolean or undefined), and does not seem to forward the transition property to the motion.div from framer motion as it did before.

RobinMalfait commented 1 day ago

Hey!

Unfortunately the way the as prop works means that we merge all the props from our component ComboboxOptions and the underlying component motion.dev. This means that technically speaking every new feature we add could lead to problems when prop names collide.

The good thing is that the as={Component} prop is just a shorthand, but you can write the tiny bit longer form to make it work:

<ComboboxOptions as={Fragment}>
  <motion.div     
    transition={{ease: "linear", duration: 2}}
    initial={{ y: -20, opacity: 0 }}
    animate={{ y: 0, opacity: 1 }}
    exit={{ y: -20, opacity: 0 }}>
    …
  </motion.div>
</ComboboxOptions>

Whenever you use as={Fragment}, Headless UI will forward the internal DOM related props to the first child, in this case motion.div, but this will only include DOM related props such as attributes (aria-*, data-*, ...) and event listeners (onClick, ...)

This way the transition prop doesn't conflict.

Hope this helps!