GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — fix(hub-ui,json-render-ui): FloatingPopover escapes a transformed ancestor's containing block; native Select mode by antfubot · Pull Request #228 · devframes/devframe

Conversation

@antfubot

@antfubot antfubot commented Aug 14, 2026

Copy link
Copy Markdown
Collaborator

What changed

  • FloatingPopover (hub-ui) resolves the outermost ancestor that forms a containing block for position: fixed descendants and <Teleport>s its panel into that ancestor's parent. With no such ancestor, it renders in place as before.
  • Select (json-render-ui) gains native, rendering a real <select> instead of FormSelect/FormCombobox. It has no icon, description or searchable support.
  • SelectPropsSchema (json-render) gains the matching native field, so a spec can opt an element into it and the tsnapi API snapshot is updated.
  • New Storybook story (EscapesTransformedAncestor) demonstrating the escape fix against a transformed, overflow-clipping ancestor.

Why it changed

A position: fixed panel is positioned relative to its nearest ancestor carrying a non-none transform/filter/contain, not the viewport, and is clipped by that ancestor's overflow. Any of FloatingPopover's current consumers — the dock overflow panel, group popover, context menu, edge-position dropdown — would be mispositioned and clipped if rendered inside such an ancestor. Escaping the outermost rather than the nearest such ancestor matters because escaping one can land inside another. Walking parentElement (not parentNode) naturally stops at a shadow root's boundary, so the teleport target stays inside the dock's shadow root — where its stylesheet is scoped — rather than escaping to document.body and losing its styling.

native on Select is an escape hatch worth having regardless: the browser draws a native option list outside the page's layout, so no ancestor can clip or misposition it at all — the dependable choice for a Select embedded in a host layout this component doesn't control.

Porting notes

This ports vitejs/devtools#518 ("fix(core): FloatingPopover escapes a transformed ancestor's containing block; native Select mode" by @dvcolomban), per #205. That PR targeted packages/core/src/client/webcomponents/** in vitejs/devtools, which moved here as packages/hub-ui/src/client/components/floating/** and packages/json-render-ui/src/components/Select.ts in the v0.9 migration.

Adapted rather than ported verbatim:

  • The original PR's surface prop on FloatingPopover (tooltip | menu) and Select's dropdown switching to surface="menu" don't have an equivalent here — this fork's Select renders through @antfu/design's FormSelect/FormCombobox (reka-ui popovers), not through FloatingPopover, so there's no consumer to point a menu surface at. FloatingPopover's own five menu-style consumers (dock overflow, group popover, context menu, edge-position dropdown) are left as-is — restyling their padding is a separate, visually-verifiable change I didn't want to bundle into a positioning bug fix.
  • native's styling is written against this fork's design-system semantic classes (border-base, bg-base, color-base, …) per this repo's conventions, rather than the upstream fix's inline styles.
  • Worth flagging: @antfu/design's FormSelect/FormCombobox (reka-ui SelectPortal/ComboboxPortal) default to portalling into document.body, which suffers the same class of positioning/clipping bug inside a shadow root or transformed ancestor. Fixing that is out of scope here (it's an upstream dependency, not first-party code) but may be worth its own follow-up issue.

Credit to @dvcolomban for the original fix and rationale.

Closes #205


Prepared with the help of an agent.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@antfubot @dvcolomban
fix(hub-ui,json-render-ui): FloatingPopover escapes a transformed anc…
43b8386
…estor's containing block; native Select mode

`FloatingPopover` (hub-ui) is positioned `fixed` against its anchor's viewport rect, but a
`transform`/`filter`/`contain` ancestor makes itself the containing block for that
`position: fixed`, so the panel ends up positioned relative to — and clipped by — that
ancestor instead of the viewport. `resolveFixedEscapeTarget` walks up from the anchor to the
outermost such ancestor (escaping only the nearest one can land inside another) and
`<Teleport>`s the panel to its parent; walking `parentElement` stops at a shadow root's
boundary, so a dock's popover never escapes the shadow root its stylesheet is scoped to. With
no such ancestor, the panel renders in place as before.

`Select` (json-render-ui) gains `native`, rendering a real `<select>` instead of
`FormSelect`/`FormCombobox`: the browser draws its option list outside the page's layout, so
no ancestor can clip or reposition it at all — a dependable escape hatch for a `Select`
embedded in a host layout this component doesn't control, at the cost of `icon`,
`description` and `searchable`, which have no native equivalent.

Ports vitejs/devtools#518, adapted to this fork: that PR's `surface` prop and `Select`'s
switch to it don't have an equivalent here — this fork's `Select` renders through
@antfu/design's `FormSelect`/`FormCombobox` (reka-ui popovers), not through
`FloatingPopover`, so there's no consumer to point at a menu surface. (Those reka-ui
popovers default to portalling into `document.body`, which suffers the same class of bug
inside a shadow root or a transformed ancestor — worth a follow-up, but out of scope for a
first-party fix here.)

Closes #205

Co-authored-by: dvcolomban <[email protected]>
@netlify

netlify Bot commented Aug 14, 2026 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown

✅ Deploy Preview for devfra ready!

Name Link
🔨 Latest commit 43b8386
🔍 Latest deploy log https://app.netlify.com/projects/devfra/deploys/6a7f00d7d7566c0008e8f427
😎 Deploy Preview https://deploy-preview-228--devfra.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

antfu
antfu approved these changes Aug 15, 2026
View reviewed changes
@antfu
antfu merged commit 648ec5c into main Aug 15, 2026
12 checks passed

Uh oh!

There was an error while loading. Please reload this page.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

@antfu antfu antfu approved these changes

Uh oh!

There was an error while loading. Please reload this page.

Assignees

No one assigned

Labels

None yet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

Port fix from vitejs/devtools#518: FloatingPopover escapes a transformed ancestor's containing block; native Select mode

Uh oh!

There was an error while loading. Please reload this page.

2 participants

@antfubot @antfu
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.
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.