Summary
Components that rely on position: absolute with safe-area-based dimensions (BottomSheet, BottomSheetDialog, BottomSheetOverlay) render incorrectly or are invisible in the web Storybook (@storybook/react-native-web-vite). The same components work correctly in the iOS Storybook.
Affected components
BottomSheet — dialog not visible after opening
BottomSheetDialog — never visible (auto-opens on mount but stays off-screen)
BottomSheetOverlay — backdrop not visible
Root cause
Two related problems:
1. CSS positioning context
On iOS, React Native's position: absolute is always relative to the direct parent component. On web (via react-native-web), it follows CSS rules and needs a positioned ancestor (position: relative/absolute/fixed).
The GestureHandlerRootView + SafeAreaProvider chain in preview.tsx does not establish a reliable positioned CSS context with a defined height, so absolute inset-0 / absolute bottom-0 inset-x-0 resolve to the wrong ancestor.
2. useSafeAreaFrame() returns window dimensions on web
BottomSheetDialog uses:
const { height: screenHeight } = useSafeAreaFrame();
const maxSheetHeight = screenHeight - screenTopPadding;
On web, useSafeAreaFrame() returns the browser window dimensions rather than the story canvas dimensions. This causes:
maxHeight: maxSheetHeight to be calibrated to the full window height, not the preview iframe
- The animation
translateY start/end values to be off
maxHeight: 0 if SafeAreaProvider hasn't initialized yet on first render
Expected behaviour
BottomSheetDialog slides up from the bottom of the preview canvas and is fully visible, matching the iOS behaviour (without gesture/animation fidelity — that's expected on web).
Proposed fix
Two options to evaluate:
Option A — Story-level fix (lower risk):
Add a position: relative wrapper with a defined height to the affected stories' decorators on web, e.g.:
decorators: [
(Story) => (
<View style={{ flex: 1, position: 'relative' }}>
<Story />
</View>
),
],
Option B — Component-level fix (correct long-term):
Branch on Platform.OS === 'web' in BottomSheetDialog to skip useSafeAreaFrame and use layout-relative sizing instead:
const screenHeight = Platform.OS === 'web'
? containerHeight // measured via onLayout on the parent
: useSafeAreaFrame().height;
Option A is safer as a patch; Option B is more correct and would also benefit production web usage.
Context
Discovered while enabling web Storybook in PR #1134. The iOS Storybook remains the source of truth for these components in the meantime.
Related PR: #1134
Upstream tracking: dannyhw/vite-plugin-rnw#13
Summary
Components that rely on
position: absolutewith safe-area-based dimensions (BottomSheet,BottomSheetDialog,BottomSheetOverlay) render incorrectly or are invisible in the web Storybook (@storybook/react-native-web-vite). The same components work correctly in the iOS Storybook.Affected components
BottomSheet— dialog not visible after openingBottomSheetDialog— never visible (auto-opens on mount but stays off-screen)BottomSheetOverlay— backdrop not visibleRoot cause
Two related problems:
1. CSS positioning context
On iOS, React Native's
position: absoluteis always relative to the direct parent component. On web (viareact-native-web), it follows CSS rules and needs a positioned ancestor (position: relative/absolute/fixed).The
GestureHandlerRootView+SafeAreaProviderchain inpreview.tsxdoes not establish a reliable positioned CSS context with a defined height, soabsolute inset-0/absolute bottom-0 inset-x-0resolve to the wrong ancestor.2.
useSafeAreaFrame()returns window dimensions on webBottomSheetDialoguses:On web,
useSafeAreaFrame()returns the browser window dimensions rather than the story canvas dimensions. This causes:maxHeight: maxSheetHeightto be calibrated to the full window height, not the preview iframetranslateYstart/end values to be offmaxHeight: 0ifSafeAreaProviderhasn't initialized yet on first renderExpected behaviour
BottomSheetDialogslides up from the bottom of the preview canvas and is fully visible, matching the iOS behaviour (without gesture/animation fidelity — that's expected on web).Proposed fix
Two options to evaluate:
Option A — Story-level fix (lower risk):
Add a
position: relativewrapper with a defined height to the affected stories' decorators on web, e.g.:Option B — Component-level fix (correct long-term):
Branch on
Platform.OS === 'web'inBottomSheetDialogto skipuseSafeAreaFrameand use layout-relative sizing instead:Option A is safer as a patch; Option B is more correct and would also benefit production web usage.
Context
Discovered while enabling web Storybook in PR #1134. The iOS Storybook remains the source of truth for these components in the meantime.
Related PR: #1134
Upstream tracking: dannyhw/vite-plugin-rnw#13