Fix Vue <Portal>
SSR hydration mismatches
#2700
Merged
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
The
<Portal>
component in@headlessui/vue
uses Vue's native<Teleport>
component. However, SSR for Teleport is somewhat complicated and requires cooperation between the library / code using it and the "server" rendering the Vue app for SSR. Tools like Nuxt support SSR-ing<Teleport>
but only under certain circumstances. Unfortunately with how we use portals in Headless UI supporting SSR properly would be rather complicated if it's possible at all.Right now, when used in Nuxt, you can get a hydration error if the thing that's using a Portal is "immediately visible". This means that when Vue goes to hydrate the DOM you'll get a warning in the console like this:
The Vue docs discuss SSR and
<Teleport>
in the context of SSR specifically and one of the recommendations is delay mounting of Teleport until the component is mounted.So, in this PR, we've updated our
<Portal>
component to defer mounting the portal content until after the component has mounted in the DOM to ensure it matches during SSR hydration.