From a34faa8fba4b7df2228bd914f72150d42839814d Mon Sep 17 00:00:00 2001 From: Heikki Lampinen Date: Wed, 4 Nov 2026 16:48:26 +0200 Subject: [PATCH] Show the iOS sheet grabber only on a sheet that can be resized The bottom sheet forced `.presentationDragIndicator(.visible)`, so every sheet had a grabber, also one with a single detent that can't be dragged to another height. Apple's HIG (Sheets) puts a grabber in a resizable sheet: it shows the sheet can be dragged to resize and lets VoiceOver resize it. On a sheet that can't resize it promises something that isn't there. `.automatic` leaves it to the system, which shows the grabber on the default "medium,large" sheet and hides it on a single detent ("large", "fit"). Swipe-down to dismiss works the same either way. Co-Authored-By: Claude Opus 5.5 --- resources/ios/NativeUIBottomSheetRenderer.swift | 5 ++++- tests/BottomSheetRendererTest.php | 9 +++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/resources/ios/NativeUIBottomSheetRenderer.swift b/resources/ios/NativeUIBottomSheetRenderer.swift index 0b135cb..c828c33 100644 --- a/resources/ios/NativeUIBottomSheetRenderer.swift +++ b/resources/ios/NativeUIBottomSheetRenderer.swift @@ -56,7 +56,10 @@ struct NativeUIBottomSheetRenderer: View { detents: resolveDetents(detentsStr), selection: fits ? $selectedDetent : nil )) - .presentationDragIndicator(.visible) + // The system shows the grabber only when the sheet can be + // resized, as Apple's HIG has it. A single-detent sheet has + // nothing to drag between, so a grabber would only mislead. + .presentationDragIndicator(.automatic) .interactiveDismissDisabled(permanent) .presentationBackgroundInteraction(bgInteraction ? .enabled : .automatic) .modifier(A11yLabelModifier(label: a11yLabel)) diff --git a/tests/BottomSheetRendererTest.php b/tests/BottomSheetRendererTest.php index 0b6c7e4..c259431 100644 --- a/tests/BottomSheetRendererTest.php +++ b/tests/BottomSheetRendererTest.php @@ -1,5 +1,14 @@ toBeString() + ->toMatch('/\.presentationDragIndicator\(\.automatic\)/') + ->not->toContain('.presentationDragIndicator(.visible)'); +}); + test('keeps the Android bottom sheet composed until hiding it has slid it away', function () { $rendererPath = dirname(__DIR__).'/resources/android/BottomSheetRenderer.kt';