Skip to content

[iOS 26] Sheet scaled to ~96% width at non-large detents (8pt side margins) despite presentation="page"; dimming also broken #732

Description

@kinghennry

Description

On iOS 26, UISheetPresentationController applies a scale(0.961) transform to UIDropShadowView (the sheet's presentation wrapper) at every non-large detent. This shrinks the sheet from the full screen width to ~96%, centered — leaving ~8pt margins on both sides (the new "floating sheet" look).

This happens even with presentation="page" (i.e. prefersPageSizing = YES), which should render a bottom-attached, full-width page sheet. At the large detent the transform is identity and the sheet is correctly full-width — which is why dragging a sheet up appears to "fix" it.

It affects every sheet. It's usually invisible (a dark sheet over a dark screen), but over full-bleed media (a photo/video filling the screen) those 8pt margins expose the content behind the sheet and read as broken edges.

Environment

  • @lodev09/react-native-true-sheet 3.11.6
  • iOS 26.2 SDK, iPhone 11, portrait-locked (orientation: portrait)
  • React Native 0.83 / Expo SDK 55, New Architecture (Fabric)

Reproduction

  1. Render a full-bleed image/video that fills the screen.
  2. Present a TrueSheet over it at a non-large detent — e.g. detents={['auto']} or detents={[0.7, 0.95]} — with the default presentation="page".
  3. The sheet shows ~8pt of the media on each side.
  4. Drag it to the large detent → it snaps to full width and the margins disappear.

Measured

Native RCTLogWarn dump of the presentation hierarchy at present-time (screen is 414 x 896):

feed-options (auto, bad):  UIDropShadowView f={{8,488},{398,400}} b={{0,0},{414,416}} tf=[0.961 0 0 0.961 0 0]
comments @0.7   (bad):     UIDropShadowView f={{8,252},{398,635}} b={{0,0},{414,661}} tf=[0.961 0 0 0.961 0 4.8]
comments @0.95  (OK):      UIDropShadowView f={{0,48},{414,848}}  b={{0,0},{414,848}} tf=[1.0   0 0 1.0   0 0]
plain screen    (bad):     UIDropShadowView f={{8,424},{398,464}} b={{0,0},{414,482}} tf=[0.961 0 0 0.961 0 1.3]

Note bounds is always full-width (414) — only the transform insets it. The last row is a sheet on a plain (non-media) screen: it has the identical 0.961 scale. The inset is always present; media only makes it visible.

Ruled out

  • The sheet's own frame is full-width; verticalSizeClass = Regular (not compact)
  • prefersPageSizing = 1, widthFollowsPreferredContentSizeWhenEdgeAttached = 0, preferredContentSize = {0,0} — all as TrueSheet sets them; iOS is not overriding them
  • No layer mask, no cornerRadius/maskedCorners difference between the working and broken cases
  • Setting prefersEdgeAttachedInCompactHeight = NO changes nothing (expected — the app is portrait-locked, so compact height never applies)
  • Not media-specific (see the plain-screen row above)

Second bug (related)

UIDimmingView renders with a fully transparent background (backgroundColor alpha = 0) on iOS 26, so dimmed never actually dims the backdrop — even though largestUndimmedDetentIdentifier is correctly set to nil (with dimmed=true and dimmedDetentIndex=0, per TrueSheetViewController.mm).

This is what makes bug #1 visible in practice: with a working dim, the 8pt margins would read as dark rather than exposing bright content.

Note for anyone attempting a workaround

Forcing UIDropShadowView.transform = CGAffineTransformIdentity in viewDidLayoutSubviews does not work: iOS re-applies the scale on the next layout pass (causing flicker), and mutating the wrapper's frame desyncs it from the detent/drag model (a single-detent sheet becomes draggable).

Happy to test any patch or provide more native dumps.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions