Skip to content

[ScrollView][iOS] Fix auto inset behaviour to use max of safe area inset/container padding - #59836

Merged
huntie merged 1 commit into
mainfrom
pr59836
Nov 12, 2026
Merged

huntie merged 1 commit into
mainfrom
pr59836

Conversation

@huntie

@huntie huntie commented Nov 6, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Context

Optional but intended follow-up to #59194.

#59194 fixed the documented behaviour of ScrollView/FlatList contentInsetAdjustmentBehavior by handling safe area padding across the scrollable axis, such as the rail on iPhone Duo and the notch on a regular iPhone in landscape.

Now that this works, there's a further detail on Duo which reveals a bug/misbehaviour with contentInsetAdjustmentBehavior handling and inner content padding.

This diff

Proposes a further update to contentInsetAdjustmentBehavior and how it interacts with padding set by contentContainerStyle.

image

Key change: Moves from an add padding approach to max of padding or safe area, per edge.

Illustrated — ScrollView with 20px content padding all sides + contentInsetAdjustmentBehavior="auto"

❌ Bug ❌ Bug ➖ Not a bug
file-243da8c77121ee9ee58faf249ceb3abe file-8c9279a880711b64cd24ecbd63fe251d file-5e2b89bc9f7f42fdc3874b9dc2769953
List flush against top inset — fixed here List flush against rail inset — fixed here List under header, away from top inset unchanged
❗ Breaking fix, where this combination occurs. ✅ Only applies since side inset support added in last PR, so no additional user impact. ✅ This is expected to be the vast majority of use cases for real apps.

The aim is to make React Native's scroll views work intuitively.

  • This is a hard thing for most devs to spot and remember to do. To get a high quality result requires negating the extra padding on one edge manually (i.e. Add StatusBar.getVerticalBarEdgeIOS and useVerticalBarEdgeIOS for iPhone Duo #59237).
  • Our historic "add padding" handling in iPhone landscape is arguably a bug. From our own ScrollView RNTester demos in landscape, having added horizontal padding beyond the safe area on both sides misaligns the content from relative UI such as the header nav bar.
    • This is also how UIKit treats layout margins against the safe area.

Implementation notes

  • A percentage padding still keeps its edge as styled, with no inset (same as before this stack).
  • The RNTester full screen example is updated to add a larger 20 pt padding on its content container, with its controls and rows drawn as rounded cards, to show the clamp, plus an "under header" toggle that places a custom header above the scroll view.
  • Android is untouched: its scroll view has no safe area handling across the scrollable axis to clamp.

Changelog:
[iOS][Fixed] - ScrollView: contentInsetAdjustmentBehavior now pads content by the larger of the safe area or contentContainerStyle padding. Previously, it added the two.

Test Plan

ReactCommon/react/renderer/components/scrollview/tests/ScrollContentViewTest.cpp

RNTester, ScrollView > Content Inset Adjustment Behavior

iPhone 18 Pro portrait, before after
⚠️ 20 pt green on every side, including below the status bar inset at the top ✅ Content top sits at the status bar inset, which absorbs the 20 pt
iPhone 18 Pro portrait under a custom header, before after
✅ The scroll view starts below the header, with no top inset, so the 20 pt applies ✅ Unchanged: with no inset to absorb it, the 20 pt still applies
iPhone 18 Pro landscape, before after
⚠️ Content sits 20 pt inside both safe area edges ✅ Content sits at both safe area edges, which absorb the 20 pt
iPhone Duo folded, before after
⚠️ Content stops 20 pt short of the rail: the inset and the padding add ✅ Content sits at the rail, which absorbs the 20 pt; the 20 pt stays on the open side and at the top

@huntie
huntie changed the base branch from main to pr59194 November 6, 2026 21:37
@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Nov 6, 2026
@huntie
huntie added this pull request to stack #59837 November 6, 2026 21:37
@huntie
huntie force-pushed the pr59836 branch 2 times, most recently from 6c44668 to 6b290c9 Compare November 9, 2026 21:57
@huntie
huntie marked this pull request as ready for review November 11, 2026 15:57
@huntie huntie changed the title [ScrollView][iOS] Change padding to use max of safe area inset/container value [ScrollView][iOS] Fix auto inset behaviour to use max of safe area inset/container padding Nov 11, 2026
@huntie
huntie requested a review from javache November 11, 2026 15:58
* the content container by the insets, so content is laid out clear of the
* system UI, such as the rail on iPhone Duo or camera cutout in landscape,
* while the container's background still extends edge to edge.
* while the container's background still extends edge to edge. On every

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: The docs say contentContainerStyle padding counts toward the inset “on every edge,” but percentage padding intentionally bypasses this calculation. Could we qualify this as point-valued padding or mention the percentage-padding exception?

@huntie huntie Nov 11, 2026 •

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah let me follow this up 👍🏻👍🏻

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for adding the detailed percentage-padding behavior below — that addresses the underlying nuance. One small follow-up: this sentence still says the padding counts toward the inset “on every edge,” which remains slightly over-broad because percentage padding across the scrollable axis intentionally bypasses the safe-area padding. Could we qualify this sentence as point-valued/pixel padding too?

@cipolleschi cipolleschi left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good overall. The inset calculation, RTL handling, native state propagation, and test coverage are sound. I left one non-blocking documentation nit.

@huntie

huntie commented Nov 12, 2026 •

Copy link
Copy Markdown
Collaborator Author

@huntie-bot Pick to 0.89 and 0.88 when merged. Assume #59194 is successfully picked first, by explicitly stating this dependency in the pick request with an > [!Important] callout.

Base automatically changed from pr59194 to main November 12, 2026 14:46
@huntie
huntie enabled stacked auto-merge (squash) November 12, 2026 14:46
@huntie
huntie disabled stacked auto-merge November 12, 2026 14:47
@huntie
huntie enabled stacked auto-merge (squash) November 12, 2026 14:47
stacked auto-merge was automatically disabled November 12, 2026 14:49

Pull Request is not mergeable

@facebook-github-tools facebook-github-tools Bot added the Shared with Meta Applied via automation to indicate that an Issue or Pull Request has been shared with the team. label Nov 12, 2026
@huntie
huntie enabled stacked auto-merge (squash) November 12, 2026 14:57
@cipolleschi

Copy link
Copy Markdown
Contributor

Just to set expectations, we can't pick these changes in 0.88 because it will be a breaking change.

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

Labels

CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. p: Expo Partner: Expo Partner Shared with Meta Applied via automation to indicate that an Issue or Pull Request has been shared with the team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants