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

Next.js className function problem #1575

Closed
theeldarka opened this issue May 10, 2024 · 2 comments
Closed

Next.js className function problem #1575

theeldarka opened this issue May 10, 2024 · 2 comments

Comments

@theeldarka
Copy link

What component (if applicable)

Describe the bug
I guess, Next.js has upgraded and now they don't support functions to className attribute on the client side

To Reproduce
Steps to reproduce the behavior:

  1. Start clean Next.js v14.2.3
  2. Copy & Paste React code from tailwindui.com
  3. Now, there is an error
Error: Functions cannot be passed directly to Client Components unless you explicitly expose it by marking it with "use server". Or maybe you meant to call this function rather than return it.
  <... as="header" className={function className} children=...>
@HanSeonWoo
Copy link

@theeldarka
Could this be because it's not a client component?
I can't do button actions on the server component, so I have to use the
I need to put 'use client' at the top of the page
tailwindui don't consider Next, so I have to take care of whether it's a client component or not.

@RobinMalfait
Copy link

Hey!

Unfortunately you can't pass functions/callbacks to components in server components because they are not serializable. In this case you can do a few things:

  1. Convert the component to a client component. You can do this by adding 'use client' at the top of the file.
  2. If you are using the latest Headless UI version, then you can also use the data attributes that we expose.

For example, this:

<Popover
  as="header"
  className={({ open }) =>
    classNames(
      open ? 'fixed inset-0 z-40 overflow-y-auto' : '',
      'bg-white shadow-sm lg:static lg:overflow-y-visible'
    )
  }
>

... turns into something like this:

<Popover
  as="header"
  className="data-[open]:fixed data-[open]:inset-0 data-[open]:z-40 data-[open]:overflow-y-auto bg-white shadow-sm lg:static lg:overflow-y-visible"
  {/*        ---------------------------------------------------------------------------------- */}
>

Notice how each class that used to be added based on the open state, now is added based on the data-[open]: Tailwind variant which uses the open data attribute.

In case you are showing elements conditionally, you can also use group-data in Tailwind CSS and apply the hidden class:

So code like this:

<Popover>
  {open ? (
    <XMarkIcon className="block h-6 w-6" aria-hidden="true" />
  ) : (
    <Bars3Icon className="block h-6 w-6" aria-hidden="true" />
  )}
</Popover>

... turns into this:

<Popover className="group">
  <XMarkIcon className="group-data-[open]:block hidden h-6 w-6" aria-hidden="true" />
  <Bars3Icon className="group-data-[open]:hidden block h-6 w-6" aria-hidden="true" />
</Popover>

All that said, maybe Next.js and React will one day figure out on how to serialize functions, but for now this is what you have to do.

We will also very likely convert our Tailwind UI components to make use of these data attributes which will simplify the components more.

Hope this helps!

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

3 participants