tailwindlabs / headlessui

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

Opacity of Dialog.Overaly after transition #374

Closed cding91 closed 3 years ago

cding91 commented 3 years ago

What package within Headless UI are you using?

headlessui/react

What version of that package are you using?

1.0.0

What browser are you using?

Chromium Edge

Reproduction repository

https://github.com/cding91/IssueReproduce

Description

I grabbed the example code for Dialog. The example code uses transition on the opacity of the overlay. I intend to make use opacity-50 for the final looks of the overlay. I hope overlay's opacity can transition from 0 to 50. What it did is shown in the code snippet below.

But it seems the overlay's opacity changes from 0 to 50 then flashes to 100 (see the image). Is this the right behavior that I should expect? Is there something that I should or should not do to get the right transition? Thank you.

  <Transition.Child 
    as={Fragment}
    enter="transition duration-500"
    enterFrom="opacity-0"
    enterTo="opacity-50"
    leave="transition duraiton-500"
    leaveFrom="opacity-50"
    leaveTo="opacity-0"
  >
    <Dialog.Overlay className="fixed inset-0 opacity-50 bg-gray-500" />
  </Transition.Child>

image

mattellig commented 3 years ago

I was having the same/similar issue. Something like this worked for me:

<Transition.Child
    as={Fragment}
    enter="ease-out duration-500"
    enterFrom="opacity-0"
    enterTo="opacity-100"
    leave="ease-in duration-500"
    leaveFrom="opacity-100"
    leaveTo="opacity-0"
>
    <Dialog.Overlay className="fixed inset-0 bg-gray-500 bg-opacity-50 transition-opacity" />
</Transition.Child>

Specify the desired opacity with a bg-opacity utility on the overlay itself. Animates nicely and has the desired effect.

cding91 commented 3 years ago

I was having the same/similar issue. Something like this worked for me:

<Transition.Child
    as={Fragment}
    enter="ease-out duration-500"
    enterFrom="opacity-0"
    enterTo="opacity-100"
    leave="ease-in duration-500"
    leaveFrom="opacity-100"
    leaveTo="opacity-0"
>
    <Dialog.Overlay className="fixed inset-0 bg-gray-500 bg-opacity-50 transition-opacity" />
</Transition.Child>

Specify the desired opacity with a bg-opacity utility on the overlay itself. Animates nicely and has the desired effect.

It works! Thanks.

Wonder if this is what I am supposed to be doing...

hugotiger commented 3 years ago

Hey!

I had the same issue and just wanted to note that I seem to have found the cause of the issue. When you set a opacity on the <Dialog.Overlay> it seems to override the opacity set by the <Transition.Child>-component.

One solution is doing as @mattellig suggested. Although setting transition-opacity is not needed. Either that or add a semi-transparent color value to your tailwind.config.js and use that color instead.

I don't know if this is intended behaviour or not 🤔

Best regards, Hugo

adamwathan commented 3 years ago

Hey! The issue here is the opacity-50 class that is sitting on the overlay element permanently:

Screen Shot 2021-04-17 at 3 46 44 PM

The way the transition component works, it adds the enter classes to the element at the beginning of the transition, meaning the element has these classes at first:

<Dialog.Overlay className="fixed inset-0 opacity-50 bg-gray-500 transition duration-500 opacity-0" />

Notice how both opacity-50 and opacity-0 are on the element at the same time. This is a conflict, and whichever one appears later in the CSS file happens to win, in this case opacity-50 so opacity-0 is never applied.

The solution in general it to avoid conflicting classes being on an element at the same time. Using bg-opacity-50 for the overlay is a great way to do that, another approach is to just use two separate elements, where the inner element is the actual 50% transparent overlay, and the outer element transitions from 0 to 100 opacity:

  <Transition.Child 
    as={Fragment}
    enter="transition duration-500"
    enterFrom="opacity-0"
    enterTo="opacity-100"
    leave="transition duraiton-500"
    leaveFrom="opacity-100"
    leaveTo="opacity-0"
  >
    <Dialog.Overlay className="fixed inset-0">
      <div className="absolute inset-0 opacity-50 bg-gray-500"/>
    </Dialog.Overlay>
  </Transition.Child>

Headless UI has no way to know it should remove the opacity-50 class when it starts the transition and adds the opacity-0 class because it has no idea what those class names mean or anything.

diar-kourehpaz commented 3 years ago

Another way you can fix is to replace Fragment with div

<Transition.Child
    as="div"
    ...
>