headlessui icon indicating copy to clipboard operation
headlessui copied to clipboard

Tabs panels render inconsistency in SSR context (React)

Open ruisaraiva19 opened this issue 2 years ago • 9 comments

What package within Headless UI are you using?

@headlessui/react

What version of that package are you using?

v1.6.2

What browser are you using?

Chrome

What version of React are you using?

v17.0.2

Reproduction URL

Repo: https://github.com/ruisaraiva19/remix-demo-headlessui-tabs-issue

Demo: https://remix-demo-headlessui-tabs-issue.pages.dev/

Describe your issue

Starting on version v1.6.1, the tabs panels rendering on SSR is inconsistent. There are two scenarios currently happening:

  1. When the Tab.Group defaultIndex is set to 0, it renders all tabs panels on SSR where it should only be rendering the first one. After hydration, it renders only the first tab panel which is expected. Demo
  2. When the Tab.Group defaultIndex is set to a number other than 0, it does not render any tab panel on SSR. After hydration, it renders the correct tab panel. Demo

Basically, the hydration part is working as expected, but the SSR part is rendering either everything or nothing 😅 .

Version 1.6.0 renders the correct tab panel on SSR but has the hydration issue that was fixed on version 1.6.1.

ruisaraiva19 avatar May 22 '22 18:05 ruisaraiva19

Hey! Thank you for your bug report! Much appreciated! 🙏

Will have to dig deeper into what Remix is doing exactly. On Next.js this works as expected: https://headlessui-react-np7xchvnw-tailwindlabs.vercel.app/tabs/tabs-with-pure-tailwind

When I bump react & react-dom to version 18 then it works fine for me. Is updating your React version an option for you?

RobinMalfait avatar May 22 '22 18:05 RobinMalfait

@RobinMalfait unfortunately no, I can't update React to version 18 right now.

ruisaraiva19 avatar May 22 '22 19:05 ruisaraiva19

@RobinMalfait the example that you are sharing, is that react 18?

I've experiencing the same as @ruisaraiva19 on a nextjs project, with react 17.

joggienl avatar May 30 '22 19:05 joggienl

@joggienl yes, the issue happens when using React 17

ruisaraiva19 avatar May 30 '22 19:05 ruisaraiva19

For what it is worth, it seems like this behaviour is manifesting itself only after production build, not in dev mode.

What I tried is running nextjs with npm run dev and npm run build && npm run start. If I throttle my internet via the devtools, the issue gets more vissible.

joggienl avatar May 30 '22 19:05 joggienl

I've spend a couple minutes to setup a simple and probably "stupid" stackblitz example: https://stackblitz.com/edit/nextjs-wxjhcy?file=pages/index.js

In order to "see" it, go to the terminal (in stackblitz). That should be open by default. Stop the current process (it is npx run dev). Use this command to start a production build:

rm -rf .next && NODE_ENV=production npx next build && NODE_ENV=production npx next start

It should show something similar as the first Tab example from https://headlessui.dev/react/tabs, only i've added that only a couple of times ;-)

If you refresh the example you should see a "stutter" (it goes very fast on this example, could not make it slower at this point). What could help is using devtools to set the network speed to "slow 3g". Note that at this speed you won't be able to build anything on stackblitz but you can enable that after the run start command.

On line 62 of index.js it is possible to update the value of defaultIndex. That showcases the similar behaviour that @ruisaraiva19 also showed.

joggienl avatar May 30 '22 20:05 joggienl

A little update, it seems to happen in Chrome, when running a production build. In Safari it is working as expected.

joggienl avatar May 31 '22 09:05 joggienl

Also seeing this problem in next.js. Pre-hydration all tabs are rendered. You notice the layout shift on first load of the page. Only in production build.

This is also super obvious if you disable javascript. Reproducible on the sample code: Screen Shot 2022-08-03 at 8 57 45 PM

mikebernardo-tinyhood avatar Aug 04 '22 00:08 mikebernardo-tinyhood

Even we are also facing this same issue in our production website. We are running on React 17 and using CRA.

romitkarmakar avatar Sep 15 '22 05:09 romitkarmakar

Hey, we've implemented a fix for this in React 17. There is a caveat related to Strict Mode however:

There is a limitation of React itself before v18 and how it implements Strict Mode. This is not something we can work around. I suggest you either upgrade to React 18 where this isn't a problem at all, disable Strict Mode in development, or just ignore the hydration errors. The core if the problem is how we've had to implement tab detection during SSR and Strict Mode's double rendering. React 18 doesn't have this problem because we use React 18's useId hook which uses internal mechanisms to bypass issues caused by double rendering.

Hopefully this will get rid of any issues you are seeing.

This will be available in the next tagged release. In the meantime you can test it using our insiders build (which will take a few minutes to publish): npm install @headlessui/react@insiders

thecrypticace avatar Dec 16 '22 17:12 thecrypticace