-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
[Disclosure] Nuxt SSR Hydration missmatch #2913
Comments
Same problem here. It seems the server does not reset its counter, as it keeps incrementing the id values whenever I refresh the page. |
The same thing happens for the Could this be a general problem and could the fix from #2645 ( |
Same problem here. |
Same problem here. It could be unrelated - but I believe this issue started showing up when I upgraded to Nuxt 3.9 (and thus Vue 3.4, vite 5 etc) |
This problem also occurs on the MenuButton, MenuItems, and MenuItem components on Nuxt. |
Also occurs on |
Same problem for me as well. Anyone find a temporary fix for this until the library gets patched? |
@brettshepherd I found a workaround. It's not perfect, but at least it works. I put the problematic parts of the template into To workaround that layout problem, I use <ClientOnly>
<Menu as="div" class="..." v-bind="$attrs">
...
<MenuButton class="...">
<EllipsisVerticalIcon class="h-5 w-5" aria-hidden="true" />
</MenuButton>
...
</Menu>
<template #fallback>
<div class="h-5 w-5" /> <-- the same width/height as the <MenuButton>, that will be rendered only on the Client
</template>
</ClientOnly> I'm not happy with this workaround at all. Looking forward for the fix of this issue. 👍 |
as a temp workaround you can globally override vue version in your ...
"overrides": {
"vue": "^3.3.13"
},
... |
I briefly mentioned that in my video about the Vue 3.4 hydration updates. These warnings are "no problem" for now and ideally will be fixed when Vue provides a way to generate random id's which can be easily passed over from server to the client. Functionality-wise, things should work as before as the "hydration problems" existed before but weren't checked from Vue. Possibly, a similar approach to https://github.com/danielroe/vue-bind-once could be taken to stabilize the ID generation until Vue (probably 3.5) will provide a native method. |
Just encountered this issue, with tab component (HeadlessTab)
|
Nuxt |
Maybe it will also land in vue in time 🤞 |
Hey folks! 👋 Thanks for reporting this issue and sharing this extra information. The issueHere is the issue as I understand it today: Vue.js improved its hydration issue detection in v3.4, which is why these warnings started appearing. If you downgrade to Vue.js v3.3, you won't see these warnings anymore, although technically the SSR hydration issues still exist. These improvements in Vue.js v3.4 are highlighting an SSR id generation issue in Headless UI. Right now Headless UI uses a global incrementing id: headlessui/packages/@headlessui-vue/src/hooks/use-id.ts Lines 1 to 8 in edbcb81
And while this guarantees that the ids are unique, it doesn't guarantee that they will be the same on both the server and client. And when they don't match, a hydration warning is shown. Vue.js fix coming in v3.5Unfortunately there isn't a reliable way today for us to generate an SSR-friendly unique id in Headless UI, as we don't have control over the server. What we really need is something like React's Fortunately, there's some good news! According to this tweet from Evan You, it sounds like Vue.js will be adding a Temporary fix in NuxtAs noted elsewhere in this issue, Nuxt (which does have control over the server) has come up with their own While this new That said, we're currently working on a solution for Nuxt users where you'll be able to "provide" Headless UI with this more reliable We actually already have a working prototype locally. This is what it will look like to implement in your Nuxt projects: Note This doesn't actually exist in Headless UI yet, this is coming soon! <!-- app.vue -->
<template>
<Switch>
<!-- .... -->
</Switch>
</template>
<script setup>
import { Switch } from '@headlessui/vue'
provide('headlessui.useid', () => useId('myapp-'))
</script> If all goes well, this temporary fix could be available as early as tomorrow. Just keep in mind that you'll need to be on the latest version of Nuxt (at least v3.10) plus, of course, the latest version of Headless UI when we get that out. |
Hey @reinink. That's great news! I should also mention, that there is a Nuxt Module for Headless UI (https://github.com/P4sca1/nuxt-headlessui) and I think it can incorporate that temporary fix. |
Once the proposed temporary solution @reinink mentioned is available, I will try to incorporate it into the Nuxt HeadlessUI module to make use of it. |
Hey folks! As promised, we've got a fix in place for this as of We decided to create a small <!-- app.vue -->
<template>
<Switch>
<!-- .... -->
</Switch>
</template>
<script setup>
import { Switch, provideUseId } from '@headlessui/vue'
provideUseId(() => useId())
</script> As mentioned yesterday, make sure you're on the latest version of both Headless UI and Nuxt: npm install @headlessui/vue@latest nuxt@latest We're currently working on Headless UI v2.0, but that will likely come out officially after Vue.js v3.5, so in all likelihood we will just use the native Going to close this issue now, but please report back if you have any further issues 👍 |
@reinink Can you clarify, please, where to put this Should it be present in every component, that uses any headlessui component? Or it is enough to call it just once at a global level (such as |
@xak2000 It uses provide() and inject() internally so it's sufficient to call it once in the top-most component in your app. e.g. |
@reinink I am still getting hydration missmatches even after the fix: This is what it looks like now your provided solution for nuxt: The question remains if this is an issue with useId or with headlessui ? |
@mwohlan can you provide a reproduction? |
https://stackblitz.com/edit/github-bbxtfw?file=app.vue Okay this seems to be an issue with the nuxt-headlessui module. Importing the the components explicitly from headless-ui fixes the hydration missmatch. This is kinda weird since I forced the module to use the fixed version... |
Appreciate this is not Nuxt but if you ran into this issue (like me) using: You can add the But until its fixed permanently it cleans up the console Example:
I am by no means a frontend pro, so I don't know if this will have any knock on effects, but everything seems to be working for my nav opening etc. |
The
I can't find out why the same value but with |
@zenire it's not optimal, but we were having issues with both We are working with the following. // app.vue
import { provideUseId } from '@headlessui/vue'
provideUseId(() => useId().replace(/[-:]/, '_')) |
Thnx @danschalow I also discovered this issue just now: nuxt/nuxt#26315 |
@danschalow Is this a temporary fix until the SSR issue is fixed, or is this line something we're going to have to always add? |
Does the release of Vue 3.5 change anything for this? A stable |
I seen the last @headlessui/[email protected] switched to use Vue's Such as:
I didn't tried |
I encountered the same problem. I found that this problem occurred when I encapsulated the headless tab into a component and called it repeatedly. I wonder if this can help you. |
What package within Headless UI are you using?
@headlessui/vue
What version of that package are you using?
insiders but its the same with 1.7.16
What browser are you using?
See Stackblitz
Reproduction URL
https://stackblitz.com/edit/github-ng1nkc?file=app.vue
Describe your issue
The server rendered ids for the button and panel differ from what is expected on the client causing a hydration missmatch warning/error in the console:
Could be related to #2624 and #2645
The text was updated successfully, but these errors were encountered: