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
- Render a full-bleed image/video that fills the screen.
- 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".
- The sheet shows ~8pt of the media on each side.
- 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.
Description
On iOS 26,
UISheetPresentationControllerapplies ascale(0.961)transform toUIDropShadowView(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-sheet3.11.6orientation: portrait)Reproduction
TrueSheetover it at a non-large detent — e.g.detents={['auto']}ordetents={[0.7, 0.95]}— with the defaultpresentation="page".Measured
Native
RCTLogWarndump of the presentation hierarchy at present-time (screen is414 x 896):Note
boundsis 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
verticalSizeClass = Regular(not compact)prefersPageSizing = 1,widthFollowsPreferredContentSizeWhenEdgeAttached = 0,preferredContentSize = {0,0}— all as TrueSheet sets them; iOS is not overriding themcornerRadius/maskedCornersdifference between the working and broken casesprefersEdgeAttachedInCompactHeight = NOchanges nothing (expected — the app is portrait-locked, so compact height never applies)Second bug (related)
UIDimmingViewrenders with a fully transparent background (backgroundColoralpha =0) on iOS 26, sodimmednever actually dims the backdrop — even thoughlargestUndimmedDetentIdentifieris correctly set tonil(withdimmed=trueanddimmedDetentIndex=0, perTrueSheetViewController.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 = CGAffineTransformIdentityinviewDidLayoutSubviewsdoes 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.