Skip to content

feat: render exact initial layout in the first Fabric commit - #540

Open
kbrattli wants to merge 3 commits into
LegendApp:mainfrom
kbrattli:feat/exact-initial-layout
Open

feat: render exact initial layout in the first Fabric commit#540
kbrattli wants to merge 3 commits into
LegendApp:mainfrom
kbrattli:feat/exact-initial-layout

Conversation

@kbrattli

@kbrattli kbrattli commented Sep 3, 2026

Copy link
Copy Markdown

Closes #539.

Problem

Fabric can commit a list before the ordinary viewport measurement and initial-scroll bootstrap have converged. In transparent modal transitions, a non-zero initialScrollIndex can therefore expose an empty or incorrect page before the requested item appears, even when the viewport and every item size are already known before mount.

estimatedListSize cannot guarantee this behavior because it is a performance hint rather than a correctness contract.

User-facing impact

Applications with exact fixed geometry can opt into experimental_exactInitialLayout={{ width, height }} so the requested non-zero initial item is present in the first native commit instead of flashing during the opening transition.

Existing applications are unchanged unless they opt in.

Reproduction / evidence

To test, run https://github.com/kbrattli/react-native-smooth-clip-view with and without the LegendList patch.

The reproduction opens the third city in a horizontal fixed-size list inside a transparent modal route:

https://github.com/kbrattli/react-native-smooth-clip-view/blob/ff0f76b7b8f1a76fe8be5f9c64f29ee142286d72/example/src/components/ZoomOverlay.tsx

Before

zoom-third-city-legendlist-unpatched-pre-d594.mp4

After

zoom-third-city-legendlist-patched-d594.mp4

Fix

The opt-in exact-layout path resolves before mount and synchronously:

  • validates the declared viewport, fixed item sizes, data, and index-based initial target;
  • seeds item sizes and positions, total content extent, internal scroll state, and the target render window;
  • allocates the initial container pool from the exact average item size;
  • supplies the target native contentOffset in the first commit;
  • makes proven initial content visible while keeping interaction, onLoad, adaptive rendering, and normal readiness gated;
  • verifies the measured viewport and observed native offset before allowing iOS to finish without a corrective scroll.

Safety and fallback behavior

The path is native Fabric-only, single-column, fixed-size, and explicitly experimental. It falls back to the existing bootstrap path, with one-time development warnings, for invalid dimensions or indices, old architecture, web, horizontal RTL, headers, footers, separators, gaps, insets, refresh controls, custom layout or scroll components, sticky or snap indices, window scrolling, anchored end space, end alignment, and measured viewport mismatches.

Android intentionally keeps its existing final corrective scroll even when the seeded offset matches. iOS skips that scroll only after the declared viewport, relevant measured rows, resolved offset, and observed native offset all agree.

Tests

  • bun test __tests__/core/exactInitialLayout.native.test.tsx __tests__/core/bootstrapInitialScroll.test.ts __tests__/components/LegendList.bootstrapInitialScroll.test.tsx __tests__/components/Containers.native.test.tsx — 68 passed
  • bun run tsc:src — passed
  • bun run lint — 458 files checked, no fixes required
  • bun test — 1,649 passed across 119 files
  • bun run build — passed
  • Rebuilt declarations are byte-identical to the downstream patched 3.3.10 artifacts; all generated JavaScript bundle variants are AST-identical, with only generated formatting differences. No dist/ files are committed.
  • bun run prep-changelog — reported that version 3.3.10 already exists in CHANGELOG.md, so no post-release entry was added.

Add an opt-in exact viewport contract for fixed-size initial-scroll lists. Seed item geometry, content size, containers, and the native offset before mount while retaining the existing bootstrap path for unsupported or mismatched layouts.
Exercise exact snapshot resolution, unsupported fallbacks, first-commit geometry seeding, native visibility gating, viewport invalidation, and the iOS/Android bootstrap settlement split.
Keep the exact-layout hook unconditional for stable hook ordering while platform-resolved guards remove native-only lifecycle work from unsupported bundles.
@chatgpt-codex-connector

Copy link
Copy Markdown

Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits.
Credits must be used to enable repository wide code reviews.

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.

LegendList content becomes visible after a Fabric mount animation has started

1 participant