Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Twin.macro is not working with @headlessui/react #349

Closed
bipinrajbhar opened this issue Mar 4, 2021 · 6 comments
Closed

Twin.macro is not working with @headlessui/react #349

bipinrajbhar opened this issue Mar 4, 2021 · 6 comments

Comments

@bipinrajbhar
Copy link

I am using Transition component but the styles are not applied to enter, enterFrom, enter, etc.

can anybody help?.

@ben-rogerson
Copy link
Owner

ben-rogerson commented Mar 4, 2021

With Emotion you can use their ClassNames import:

import { ClassNames } from '@emotion/react'

<ClassNames>
  {({ css }) => (
    <Transition
      show={isOpen}
      enter={css(tw`transform transition ease-out duration-200`)}
      enterFrom={css(tw`opacity-0 translate-y-1`)}
      enterTo={css(tw`opacity-100 translate-y-0`)}
      leave={css(tw`transform transition ease-in duration-150`)}
      leaveFrom={css(tw`opacity-100 translate-y-0`)}
      leaveTo={css(tw`opacity-0 translate-y-1`)}
      tw="absolute z-10 -ml-4 mt-3 w-screen max-w-md lg:max-w-3xl"
    >
      <div tw="rounded-lg shadow-lg ring-1 ring-black ring-opacity-5 overflow-hidden">
        <!-- snip -->
      </div>
    </Transition>
  )}
</ClassNames>

or something like this with styled-components:

import { createGlobalStyle } from 'styled-components'

const Globals = createGlobalStyle`
  .enter {
    ${tw`transform transition ease-out duration-200`}
  }
  .enterFrom {
    ${tw`opacity-0 translate-y-1`}
  }
  .enterTo {
    ${tw`opacity-100 translate-y-0`}
  }
  .leave {
    ${tw`transform transition ease-in duration-150`}
  }
  .leaveFrom {
    ${tw`opacity-100 translate-y-0`}
  }
  .leaveTo {
    ${tw`opacity-0 translate-y-1`}
  }
`

// In your app

<Globals />

<Transition
show={isOpen}
enter="enter"
enterFrom="enterFrom"
enterTo="enterTo"
leave="leave"
leaveFrom="leaveFrom"
leaveTo="leaveTo"
tw="absolute z-10 -ml-4 mt-3 w-screen max-w-md lg:max-w-3xl"
>

@bipinrajbhar
Copy link
Author

Thank you so much you guys are awesome.

@neldeles
Copy link

neldeles commented Jun 28, 2021

Tangent to this, this is the workaround I'm using for the Listbox HeadlessUI component. Was trying to use one of TailwindUI's Dropdown components which is built upon HeadlessUI's Listbox.

import { ClassNames } from "@emotion/react"

+ <ClassNames>
+  {({ css }) => (
    <Transition
      show={open}
      as={Fragment}
-     leave="transition ease-in duration-100"
-     leaveFrom="opacity-100"
-     leaveTo="opacity-0"
+    leave={css(tw`transition ease-in duration-100`)}
+    leaveFrom={css(tw`opacity-100`)}
+    leaveTo={css(tw`opacity-0`)}
    >
      <Listbox.Options
        static
        tw="absolute z-10 mt-1 w-full bg-white shadow-lg max-h-60 rounded-md py-1 text-base ring-1 ring-black ring-opacity-5 overflow-auto focus:outline-none sm:text-sm"
      >
        {people.map(person => (
          <Listbox.Option
            key={person.id}
-            className={({ active }) =>
-              classNames(
-              active ? 'text-white bg-indigo-600' : 'text-gray-900',
-              'cursor-default select-none relative py-2 pl-3 pr-9'
-              )
-            }
            value={person}
          >
            {({ selected, active }) => (
-              <>
+              <div
+                css={[
+                  tw`cursor-default select-none relative py-2 pl-3 pr-9`,
+                  active && tw`text-white bg-indigo-600`,
+                  !active && tw`text-gray-900`,
+                ]}
+              >
                <span
                  css={[
                    tw`block truncate`,
                    selected && tw`font-semibold italic`,
                    !selected && tw`font-normal`,
                  ]}
                >
                  {person.name}
                </span>

                {selected ? (
                  <span
                    css={[
                      tw`absolute inset-y-0 right-0 flex items-center pr-4`,
                      active && tw`text-white`,
                      !active && tw`text-indigo-600`,
                    ]}
                  >
                    <CheckIcon tw="h-5 w-5" aria-hidden="true" />
                  </span>
                ) : null}
-              </>
+              </div>
            )}
          </Listbox.Option>
        ))}
      </Listbox.Options>
    </Transition>
  )}
+ </ClassNames>

UPDATE: There's a way to make it not a workaround and the example's right in the docs (https://headlessui.dev/react/listbox#styling-the-active-and-selected-option).

Listbox.Option by default renders as a <li> element. But if you pass in the as={Fragment} prop value, it becomes..a fragment. Then in the render prop func you can just explicitly wrap everything in a <li> and style via tw css prop normally. No extra nested div's needed.

<Listbox.Option
  key={person.id} 
  value={person} 
+  as={Fragment}
>
  {({ active, selected }) => (
    <li
-      className={`${
-        active ? 'bg-blue-500 text-white' : 'bg-white text-black'
-      }`}
+       css={[
+         active && tw`bg-blue-500 text-white`,
+         !active && tw`bg-white text-black`
+       ]}
    >
      {selected && <CheckIcon />}
      {person.name}
    </li>
  )}
</Listbox.Option>

@lamualfa
Copy link

@ben-rogerson How about Stitches? How can i implent it?

@lamualfa
Copy link

Ok, i found it how to use it in Stitches.

In Stitches, you can use like this:

import tw, { css } from 'twin.macro'

<Transition
  enter={css(tw`transition-opacity duration-75`)().toString()}
  enterFrom={css(tw`opacity-0`)().toString()}
  enterTo={css(tw`opacity-100`)().toString()}
  leave={css(tw`transition-opacity duration-150`)().toString()}
  leaveFrom={css(tw`opacity-100`)().toString()}
  leaveTo={css(tw`opacity-0`)().toString()}
></Transition>

@ben-rogerson
Copy link
Owner

I've pushed up a new headless ui example which shows how the official component can be wrapped for use with twin.macro.
Check it out here →

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants