ui-menu crashes when cloneNode creates a detached custom element
- Dominant language
- Blade
- Stars
- 977
- Forks
- 112
- Avg merge
- 1d 4h
- Merged PRs (30d)
- 21
Description
### Flux version
v2.19.0, still present in v2.20.0
### Livewire version
v4.4.4
### Tailwind version
v4.3.3
### Browser and Operating System
WebKit 26.6 on Linux (Playwright). The same error is reported from Safari 26.6 on iOS 18.7.
### What is the problem?
`ui-menu` throws during custom-element construction when `cloneNode(true)` creates a detached clone:
```
TypeError: null is not an object (evaluating 'this.parentElement.localName')
```
The menu's `boot()` reads `this.parentElement.localName` without checking that a parent exists. Native `cloneNode()` constructs the clone while it is detached, so `parentElement` is `null`. Safari extensions that inspect or copy menu DOM trigger this on otherwise ordinary Flux dropdowns.
The same unguarded code is in every v2.20.0 runtime bundle: `flux/dist/flux.min.js`, `flux/dist/flux-lite.min.js`, `flux-pro/dist/flux.js` and `flux-pro/dist/flux.module.js`.
### Code snippets to replicate the problem
Render an ordinary Flux dropdown:
```blade
Open
One
Two
```
After Flux has initialized, run:
```js
const menu = document.querySelector('ui-dropdown ui-menu')
const clone = menu.cloneNode(true)
console.log(clone.parentElement) // null
```
In WebKit, `cloneNode(true)` returns the detached clone and also reports the uncaught TypeError above. Playwright's `page.on('pageerror', ...)` captures it deterministically.
The relevant code:
```js
if (this.parentElement.localName === "ui-dropdown") {
const dropdown = this.parentElement
// bind dropdown trigger keyboard behavior...
}
```
### Suggested fix
The minimal guard stops the exception:
```diff
-if (this.parentElement.localName === "ui-dropdown") {
+if (this.parentElement?.localName === "ui-dropdown") {
```
On its own, though, a menu constructed detached and inserted into a dropdown later would skip the trigger keyboard wiring. A fuller fix moves the dropdown-parent binding into the element's connected lifecycle and makes it idempotent.
### Screenshots / screen recordings
Not applicable; this is a deterministic page error during native DOM cloning.
### How do you expect it to work?
Cloning a `ui-menu` should not throw. An attached dropdown should keep ArrowDown/ArrowUp behavior, a standalone menu should keep menu keyboard behavior, and a menu constructed detached and later connected to a dropdown should get the same wiring.
### Please confirm
- [x] I have provided easy and step-by-step instructions to reproduce the bug.
- [x] I have provided code samples as text and NOT images.
- [x] I understand my bug report will be closed if I haven't met the criteria above.
Contributor guide
No contributing guide indexed for this repository
Research direction
Start at the ui-menu boot() logic described in the issue and reproduce the failure with cloneNode(true), using Playwright's page.on('pageerror') to observe it. Ensure detached cloning no longer throws, attached dropdowns retain ArrowUp/ArrowDown behavior, standalone menus retain keyboard behavior, and detached menus receive dropdown wiring after connection.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript, playwright
- Domain
- frontend, testing-qa
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 68/100