LearnNewsExamplesServices
Frontmatter
id15112
titleFloating aligned elements: RA-9 position:fixed cascade + RA-10 null target-offsetParent observer guards
stateClosed
labels
bug
assigneesneo-opus-grace
createdAtJul 12, 2026, 11:57 PM
updatedAt1:06 AM
githubUrlhttps://github.com/neomjs/neo/issues/15112
authorneo-opus-grace
commentsCount0
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]
closedAt1:06 AM

Floating aligned elements: RA-9 position:fixed cascade + RA-10 null target-offsetParent observer guards

neo-opus-grace
neo-opus-grace commented on Jul 12, 2026, 11:57 PM

Two placement-independent framework root-fixes for the alignment / floating-element subsystem, generalized out of the tab-overflow work (parent #14771, closed) so they land on their own authority. Both are generic — any floating aligned element, not just the tab-overflow control.

RA-9 — floating-button position: fixed cascade

resources/scss/src/button/Base.scss. A floating button carries both .neo-floating {position: fixed} (component/Base) and .neo-button {position: relative} (button/Base). Equal single-class specificity → .neo-button wins on source order → the floating button resolves to position: relative, pinning it to its offsetParent instead of the viewport, so alignTo lands it at the wrong coordinates. Fix: the compound .neo-button.neo-floating {position: fixed} (higher specificity) restores fixed positioning. Generic to any floating button.

RA-10 — null target-offsetParent observer guards

src/main/DomAccess.mjs. align() stores data.offsetParent = data.targetElement.offsetParent — the alignment target's layout parent — and addAligned / removeAligned observe/unobserve it via the align ResizeObserver. When the target's offsetParent is null — a position: fixed target (e.g. the floating overflow button once RA-9 pins it, when its own menu aligns to it) or a body/root target — observe(null) / unobserve(null) throws "parameter 1 is not of type 'Element'". Fix: null-guard both call sites.

Precise object model (the correction that motivated this leaf): the observed field belongs to the target, not the aligned subject. The subject's positioning (RA-9) and the target's null offsetParent (RA-10) are separate facts that co-occur when a menu aligns to a now-fixed button.

Evidence

Both fixes were exercised by the tab-overflow owner-exact-geometry L3 journey (passing on #15062's branch). The durable replay re-homes to #15099 (dense-workstation scene). No unit coverage: RA-9 is a CSS cascade (not unit-testable) and RA-10's guard is a main-thread DOM path — the e2e is the test-of-record.

Acceptance

  • A floating .neo-button.neo-floating resolves to position: fixed (RA-9).
  • Aligning to a target whose offsetParent is null does not throw (RA-10).
  • No regression in existing align behavior (owner-geometry L3 stays green when it replays under #15099).

Delivered by PR #15109. Parent #14771 (closed). Related: #15098 (tab-native successor, non-closing), #15099 (durable e2e replay).

tobiu closed this issue on 1:06 AM
tobiu referenced in commit ca98cf4 - "fix(button/main): floating-button position:fixed cascade + DomAccess null-offsetParent guards (#14771) (#15109) on 1:06 AM