Skip to content

Comments

Remove x,y from measureParentSize — fixes Fabric sticky header offset#2105

Open
thomasttvo wants to merge 3 commits intoShopify:mainfrom
thomasttvo:fix/measure-parent-size-remove-xy
Open

Remove x,y from measureParentSize — fixes Fabric sticky header offset#2105
thomasttvo wants to merge 3 commits intoShopify:mainfrom
thomasttvo:fix/measure-parent-size-remove-xy

Conversation

@thomasttvo
Copy link

@thomasttvo thomasttvo commented Feb 17, 2026

Summary

measureParentSize uses a self-relative measureLayout call (view.measureLayout(view, cb)) to get the outer container's width and height. The returned x,y from this call are always (0,0) on Paper and web — a view's position relative to itself is the origin.

The downstream firstItemOffset calculation in RecyclerView subtracted outerViewLayout.x/y, which was always a no-op (subtracting 0). This dead subtraction masked a Fabric compatibility issue: on Fabric, the self-relative measureLayout call returns the view's position in its parent instead of (0,0), corrupting firstItemOffset for any FlashList with content above it.

Proof that view.measureLayout(view, cb) returns (0,0) on Paper: thomasttvo/rn-measure-layout-bug (RN 0.81.5, RCT_NEW_ARCH_ENABLED=0)

Repro of downstream effect on sticky headers: thomasttvo/flashlist-sticky-header-repro

Related issues: #1942, #2017

Changes

  • measureParentSize now returns Size ({width, height}) instead of Layout ({x, y, width, height})
  • Removed the dead - outerViewLayout.x/y subtractions from firstItemOffset calculation
  • Renamed outerViewLayout to outerViewSize to reflect what it actually contains
  • Updated test mock to match new return type
  • Same changes applied to measureLayout.web.ts
  • Added integration tests that verify sticky headers don't activate prematurely when measureParentSize returns non-zero y (simulating Fabric with content above the FlashList). Tests cover 0px, 50px, and 100px offsets — they fail on the old code and pass with this fix.

measureParentSize uses a self-relative measureLayout call
(view.measureLayout(view, cb)) to get the view's width and height.
The x,y values from this call are always (0,0) on Paper and web since
a view's position relative to itself is the origin. The downstream
firstItemOffset calculation subtracted outerViewLayout.x/y which was
always a no-op.

Remove x,y from the return type (Layout -> Size), drop the dead
subtractions in RecyclerView, and rename outerViewLayout to
outerViewSize to reflect what it actually contains.

Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
@thomasttvo thomasttvo force-pushed the fix/measure-parent-size-remove-xy branch from 3b4a327 to 55872e4 Compare February 17, 2026 20:21
@thomasttvo thomasttvo marked this pull request as ready for review February 17, 2026 20:32
thomasttvo and others added 2 commits February 17, 2026 13:02
Tests verify that sticky headers don't activate prematurely when
measureParentSize returns non-zero y values (as it does on Fabric
when there's content above the FlashList). Covers three cases:
no content above, 50px above, and 100px above.

These tests fail on the old code (which subtracted outerViewLayout.y
from firstItemOffset) and pass with the fix.

Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
Reduce type casts, improve naming, and simplify the describe/test
structure for clarity.

Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant