Reference version

This documentation is available as Markdown for AI agents and LLMs. See the full Markdown index or append .md to any documentation URL.

BottomSheet

与 @gorhom/bottom-sheet 兼容的底部弹出层。

Android
iOS
Web
Included in Expo Go
Recommended version:
~58.0.1

一个 API 与 @gorhom/bottom-sheet 兼容的 BottomSheet 组件。它封装了平台专属的 @expo/ui 基元:Android 上的 Jetpack Compose ModalBottomSheet,以及 iOS 上的 SwiftUI BottomSheet。在 web 上,它使用 HTML <dialog> 底部弹出面板。

如果你需要更精细地控制平台专属的样式、修饰符或布局行为,请直接使用原生基元。

在变暗的屏幕上显示的底部弹出面板在变暗的屏幕上显示的底部弹出面板

安装

Terminal
- npx expo install @expo/ui
- yarn expo install @expo/ui
- pnpm expo install @expo/ui
- bun expo install @expo/ui

If you are installing this in an existing React Native app, make sure to install expo in your project.

从 @gorhom/bottom-sheet 迁移

  • 将导入语句从:

    import BottomSheet, { BottomSheetView } from '@gorhom/bottom-sheet';

    更新为使用 @expo/ui/community/bottom-sheet:

    import BottomSheet, { BottomSheetView } from '@expo/ui/community/bottom-sheet';
  • 此实现不需要来自 react-native-gesture-handler 的 GestureHandlerRootView。如果应用的其他部分需要它,可以保留。

  • 不支持 BottomSheetBackdrop、BottomSheetHandle、BottomSheetFooter、BottomSheetDraggableView、BottomSheetVirtualizedList、BottomSheetFlashList、useBottomSheetModal、useBottomSheetSpringConfigs 和 useBottomSheetTimingConfigs 等组件与 hook 导出。为了保持 API 兼容性,会导出部分相关属性类型。

基本用法

BottomSheetExample.tsx
import { useRef } from 'react'; import { Button, Text, useColorScheme, View } from 'react-native'; import BottomSheet, { BottomSheetView } from '@expo/ui/community/bottom-sheet'; export default function BottomSheetExample() { const colorScheme = useColorScheme(); const ink = { color: colorScheme === 'dark' ? '#FFFFFF' : '#000000' }; const sheetRef = useRef<BottomSheet>(null); return ( <View style={{ flex: 1 }}> <Button title="Open" onPress={() => sheetRef.current?.snapToIndex(0)} /> <BottomSheet ref={sheetRef} snapPoints={['25%', '50%', '90%']} index={-1} onChange={index => { console.log('onChange', index); }} onClose={() => { console.log('closed'); }} enablePanDownToClose> <BottomSheetView style={{ flex: 1, padding: 24, alignItems: 'center' }}> <Text style={ink}>Sheet content</Text> </BottomSheetView> </BottomSheet> </View> ); }

BottomSheetModal

从 @gorhom/bottom-sheet 的 modal API 迁移时,请使用 BottomSheetModal。它初始处于关闭状态,并通过 present() 打开。

BottomSheetModalExample.tsx
import { useRef } from 'react'; import { Button, Text, useColorScheme, View } from 'react-native'; import { BottomSheetModal, BottomSheetView } from '@expo/ui/community/bottom-sheet'; export default function BottomSheetModalExample() { const colorScheme = useColorScheme(); const ink = { color: colorScheme === 'dark' ? '#FFFFFF' : '#000000' }; const modalRef = useRef<BottomSheetModal>(null); return ( <View style={{ flex: 1 }}> <Button title="Present" onPress={() => modalRef.current?.present()} /> <BottomSheetModal ref={modalRef} snapPoints={['50%', '90%']} enablePanDownToClose> <BottomSheetView style={{ padding: 24 }}> <Text style={ink}>Modal content</Text> <Button title="Dismiss" onPress={() => modalRef.current?.dismiss()} /> </BottomSheetView> </BottomSheetModal> </View> ); }

动态尺寸

未提供 snapPoints 时,弹出面板默认会根据内容调整尺寸。请使用 BottomSheetView 作为弹出面板内容的包装组件。

DynamicBottomSheetExample.tsx
import { useRef } from 'react'; import { Button, Text, useColorScheme, View } from 'react-native'; import BottomSheet, { BottomSheetView } from '@expo/ui/community/bottom-sheet'; export default function DynamicBottomSheetExample() { const colorScheme = useColorScheme(); const ink = { color: colorScheme === 'dark' ? '#FFFFFF' : '#000000' }; const sheetRef = useRef<BottomSheet>(null); return ( <View style={{ flex: 1 }}> <Button title="Open" onPress={() => sheetRef.current?.present()} /> <BottomSheet ref={sheetRef} index={-1} enablePanDownToClose> <BottomSheetView style={{ padding: 24 }}> <Text style={ink}>This sheet sizes itself to its content.</Text> </BottomSheetView> </BottomSheet> </View> ); }

可滚动的 React Native 内容

底部弹出面板支持将 React Native FlatList 或 ScrollView(或 FlashList 或 Legend List 等高性能列表)作为子组件,以显示可滚动内容。启用 nestedScrollEnabled 后,列表会先滚动自身内容。到达顶部边缘后,剩余的拖动操作会移动弹出面板。为了兼容 @gorhom/bottom-sheet,还会导出 BottomSheetFlatList 和 BottomSheetScrollView,但它们只是 React Native 组件的直接重新导出。

BottomSheetScrollableExample.tsx
import { useRef } from 'react'; import { Button, FlatList, Text, useColorScheme, View } from 'react-native'; import BottomSheet from '@expo/ui/community/bottom-sheet'; const DATA = Array.from({ length: 50 }, (_, i) => `Item ${i + 1}`); export default function BottomSheetScrollableExample() { const colorScheme = useColorScheme(); const ink = { color: colorScheme === 'dark' ? '#FFFFFF' : '#000000' }; const sheetRef = useRef<BottomSheet>(null); return ( <View style={{ flex: 1 }}> <Button title="Open" onPress={() => sheetRef.current?.snapToIndex(0)} /> <BottomSheet ref={sheetRef} snapPoints={['50%', '90%']} index={-1} enablePanDownToClose> <FlatList nestedScrollEnabled style={{ flex: 1 }} data={DATA} keyExtractor={item => item} contentContainerStyle={{ padding: 24 }} renderItem={({ item }) => <Text style={{ ...ink, paddingVertical: 16 }}>{item}</Text>} /> </BottomSheet> </View> ); }

平台行为

@gorhom/bottom-sheet 会以内嵌方式显示在其父视图底部。此组件在 Android 和 iOS 上使用原生模态呈现,在 web 上使用 HTML <dialog>。

这是有意为之的差异。@gorhom/bottom-sheet 通过 react-native-gesture-handler 和 react-native-reanimated 管理手势与动画层,而 @expo/ui/community/bottom-sheet 则将这些行为交由 Jetpack Compose、SwiftUI 以及 web 上的 HTML <dialog> 处理。因此,此组件最适合模态底部弹出面板流程,包括使用 BottomSheet API 而非 BottomSheetModal 的调用场景。

功能AndroidiOSWeb
呈现方式Jetpack Compose 模态底部弹出面板SwiftUI sheetHTML <dialog> 底部弹出面板
吸附点映射为部分展开和完全展开状态支持提供的吸附点支持提供的吸附点
未设置 snapPoints适配内容适配内容适配内容
向下滑动关闭同时启用返回按钮和点击遮罩关闭同时启用点击背景关闭启用点击遮罩、Escape 键和向下滑动关闭
持久内嵌预览不支持不支持不支持

支持的导出项

导出项支持备注
BottomSheet在 Android 和 iOS 上使用模态呈现,在 web 上使用 HTML 对话框
BottomSheetModal初始关闭,通过 present() 打开
BottomSheetModalProvider为保持兼容性,直接渲染子项
BottomSheetView包装弹出面板内容
BottomSheetScrollView重新导出 React Native ScrollView
BottomSheetFlatList重新导出 React Native FlatList
BottomSheetSectionList重新导出 React Native SectionList
BottomSheetTextInput重新导出 React Native TextInput
useBottomSheet从 context 返回弹出面板 ref 方法
BottomSheetBackdrop原生弹出面板或 HTML 对话框会处理背景遮罩
BottomSheetHandle原生弹出面板或 HTML 对话框会处理拖动指示器
BottomSheetFooter此实现没有对应项

兼容性说明

  • 支持 snapPoints、index、onChange、onClose、onDismiss、enablePanDownToClose 和 enableDynamicSizing。
  • handleComponent={null} 会隐藏原生或 web 拖动指示器。在原生平台上不会渲染自定义手柄组件。
  • backgroundStyle 在 web 上完全生效。在 Android 上,backgroundColor 用于设置原生容器颜色。在 iOS 上,则使用系统弹出面板背景。
  • 为保持 API 兼容性,可以接受动画、过度拖动、内容平移、手柄平移、键盘行为、自定义背景遮罩、自定义背景、自定义页脚、动画值和分离式属性,但不会改变行为。

API

import BottomSheet from '@expo/ui/community/bottom-sheet';

Components

BottomSheet

Android
iOS
Web

Type: React.Element<BottomSheetProps>

Bottom sheet component. Defaults to index={0} and opens at the first snap point on mount.

Props for the BottomSheet component. API-compatible with @gorhom/bottom-sheet where native platform behavior allows.

BottomSheetProps

children

Android
iOS
Web
Type: React.ReactNode

The content to render inside the bottom sheet.

enableDynamicSizing

Android
iOS
Web
Optional • Type: boolean • Default: true

Whether the sheet should automatically size to fit its content.

enablePanDownToClose

Android
iOS
Web
Optional • Type: boolean • Default: false

Whether the sheet can be dismissed by panning down.

index

Android
iOS
Web
Optional • Type: number • Default: 0

Initial snap point index. Set to -1 to start closed.

onChange

Android
iOS
Web
Optional • Type: (index: number) => void

Called when the current snap point index changes.

onClose

Android
iOS
Web
Optional • Type: () => void

Called when the bottom sheet is fully closed.

onDismiss

Android
iOS
Web
Optional • Type: () => void

Alias for onClose for BottomSheetModal compatibility.

snapPoints

Android
iOS
Web
Optional • Type: (string | number)[]

Points for the bottom sheet to snap to, ordered from bottom to top.

BottomSheetModal

Android
iOS
Web

Type: React.Element<BottomSheetProps>

Modal variant of BottomSheet. Starts closed and opens with present().

BottomSheetModalProvider

Android
iOS
Web

Type: React.Element<{ children: React.ReactNode }>

Provider for BottomSheetModal. It renders children directly for API compatibility.

BottomSheetView

Android
iOS
Web

Type: React.Element<BottomSheetViewProps>

A wrapper for content inside a BottomSheet.

Props for the BottomSheetView content wrapper.

BottomSheetViewProps

children

Android
iOS
Web
Type: React.ReactNode

The content to render inside the bottom sheet.

enableDynamicSizing

Android
iOS
Web
Optional • Type: boolean • Default: true

Whether the sheet should automatically size to fit its content.

enablePanDownToClose

Android
iOS
Web
Optional • Type: boolean • Default: false

Whether the sheet can be dismissed by panning down.

index

Android
iOS
Web
Optional • Type: number • Default: 0

Initial snap point index. Set to -1 to start closed.

onChange

Android
iOS
Web
Optional • Type: (index: number) => void

Called when the current snap point index changes.

onClose

Android
iOS
Web
Optional • Type: () => void

Called when the bottom sheet is fully closed.

onDismiss

Android
iOS
Web
Optional • Type: () => void

Alias for onClose for BottomSheetModal compatibility.

snapPoints

Android
iOS
Web
Optional • Type: (string | number)[]

Points for the bottom sheet to snap to, ordered from bottom to top.

children

Android
iOS
Web
Type: React.ReactNode

Hooks

useBottomSheet()

Android
iOS
Web

Returns the imperative methods for the nearest BottomSheet.

Types

BottomSheetMethods

Android
iOS
Web

Imperative methods exposed by BottomSheet and BottomSheetModal refs.

PropertyTypeDescription
close() => void

Close the bottom sheet.

collapse() => void

Snap to the minimum snap point.

dismiss() => void

Dismiss the bottom sheet.

expand() => void

Snap to the maximum snap point.

forceClose() => void

Force close the bottom sheet.

present() => void

Present the bottom sheet at the first snap point.

snapToIndex(index: number) => void

Snap to a snap point by index.

snapToPosition(position: string | number) => void

Snap to a pixel value or percentage position.