Skip to content

Portal renders content before it is connected to the DOM, on subsequent renders #3681

@lukasvice

Description

@lukasvice

What package within Headless UI are you using?

@headlessui/react

What version of that package are you using?

v2.2.1

What browser are you using?

Chrome

Reproduction URL

https://codesandbox.io/p/sandbox/bold-dawn-pnjkt8

In this example, you can toggle a div that is rendered inside different portals (Headless UI, React, Floating UI, or without portal). The div logs in its ref callback if it is connected to the DOM, using the element.isConnected property.

Describe your issue

The Headless UI Portal, when rendered the second time, renders the content before connecting it to the DOM.

How to reproduce:

  1. Open the CodeSandbox and the console to check the output
  2. Click on the button "Toggle Headless Portal"
    ✅ Console output: ref | isConnected true
  3. Click the button again to hide the portal.
  4. Click the button once more to show it again.
    ⚠️ Console output: ref | isConnected false
Image

Expected Behavior:

On every render, the content should be connected to the DOM before the ref callback is invoked — just like it behaves when using:
• A standard div toggle
• A native React Portal
• A Floating UI Portal

You can use the other buttons in the CodeSandbox to see this behavior.

Actual Behavior

With Headless UI’s Portal, the initial render works as expected. But on subsequent renders, the ref is called before the content is connected to the DOM.

Real-World Impact

This behavior causes issues with React Hook Form, which filters out input elements that aren’t connected during initialization. Specifically:
• On the first open, a form inside a Headless UI dialog registers inputs correctly.
• On subsequent opens, radio inputs are no longer registered, because their ref is assigned before they’re connected to the DOM, and RHF filters them out.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions