BottomSheet
A smooth, customizable modal that slides up from the bottom
A beautiful modal component that slides up from the bottom of the screen with smooth animations and intuitive gestures. Perfect for displaying additional options, menus, filters, and forms without taking up the full screen.
Overview#
BottomSheet handles animations, touch gestures, and swipe-to-close interactions automatically. It provides a native feel with customizable content and styling.
Use it for:
- Action menus and options
- Filter and sorting panels
- Secondary forms and input
- Share sheets
- Detailed information panels
- Bottom navigation menus
Interactive Preview
9:41
With Custom Content#
import { BottomSheet, Button } from 'prizmux'
import { View, Text } from 'react-native'
import { useState } from 'react'
function ActionSheet() {
const [visible, setVisible] = useState(false)
const actions = [
{ label: 'Edit', icon: '✏️', onPress: () => {} },
{ label: 'Share', icon: '📤', onPress: () => {} },
{ label: 'Delete', icon: '🗑️', onPress: () => {} },
]
return (
<>
<Button
title="Menu"
onPress={() => setVisible(true)}
/>
<BottomSheet
visible={visible}
onClose={() => setVisible(false)}
title="Actions"
showDragHandle={true}
swipeToClose={true}
>
<View style={{ paddingHorizontal: 16, paddingBottom: 20 }}>
{actions.map((action, idx) => (
<Button
key={idx}
title={action.label}
icon={<Text>{action.icon}</Text>}
iconPosition="left"
fullWidth={true}
variant="outline"
style={{ marginBottom: 12 }}
onPress={() => {
action.onPress()
setVisible(false)
}}
/>
))}
</View>
</BottomSheet>
</>
)
}
import { BottomSheet, Button } from 'prizmux'
import { View, Text } from 'react-native'
import { useState } from 'react'
function ActionSheet() {
const [visible, setVisible] = useState(false)
const actions = [
{ label: 'Edit', icon: '✏️', onPress: () => {} },
{ label: 'Share', icon: '📤', onPress: () => {} },
{ label: 'Delete', icon: '🗑️', onPress: () => {} },
]
return (
<>
<Button
title="Menu"
onPress={() => setVisible(true)}
/>
<BottomSheet
visible={visible}
onClose={() => setVisible(false)}
title="Actions"
showDragHandle={true}
swipeToClose={true}
>
<View style={{ paddingHorizontal: 16, paddingBottom: 20 }}>
{actions.map((action, idx) => (
<Button
key={idx}
title={action.label}
icon={<Text>{action.icon}</Text>}
iconPosition="left"
fullWidth={true}
variant="outline"
style={{ marginBottom: 12 }}
onPress={() => {
action.onPress()
setVisible(false)
}}
/>
))}
</View>
</BottomSheet>
</>
)
}
With Dismiss on Outside Tap#
<BottomSheet
visible={visible}
onClose={() => setVisible(false)}
dismissOnTouchOutside={true}
showCloseButton={true}
>
<Text>Tap outside to close</Text>
</BottomSheet>
<BottomSheet
visible={visible}
onClose={() => setVisible(false)}
dismissOnTouchOutside={true}
showCloseButton={true}
>
<Text>Tap outside to close</Text>
</BottomSheet>
Without Drag Handle#
<BottomSheet
visible={visible}
onClose={() => setVisible(false)}
showDragHandle={false}
showCloseButton={true}
>
<Text>Close using the button</Text>
</BottomSheet>
<BottomSheet
visible={visible}
onClose={() => setVisible(false)}
showDragHandle={false}
showCloseButton={true}
>
<Text>Close using the button</Text>
</BottomSheet>
Props Reference#
| Prop | Type | Default | Description |
|---|---|---|---|
visible | boolean | false | Control sheet visibility |
onClose | () => void | Required | Called when sheet is dismissed |
title | string | - | Optional header title |
children | ReactNode | Required | Sheet content |
dismissOnTouchOutside | boolean | true | Close when tapping backdrop |
showCloseButton | boolean | true | Display close button |
showDragHandle | boolean | true | Show drag handle indicator |
swipeToClose | boolean | true | Enable swipe-to-close gesture |
closeIcon | ReactNode | - | Custom close button icon |
backgroundColor | string | #FFF | Background of the sheet |
backdropColor | string | - | Overrides default semi-transparent gray |
textColor | string | - | Fallback color for header title text |
borderColor | string | - | Optional border around the sheet |
borderRadius | number | 20 | Top corner radius |
showHeaderBorder | boolean | true | Toggle the bottom border of the header |
headerBorderBottomColor | string | - | Custom color for header separator |
closePosition | 'left' | 'right' | 'right' | Extreme edge alignment for close |
titlePosition | 'left' | 'center' | 'right' | 'left' | Alignment for title |
High-Responsiveness Dragging#
Prizmux BottomSheets support High-Responsiveness Dragging: The entire surface area of the sheet (not just the handle) can be swiped down to dismiss, ensuring a smooth and forgiving user experience.
Styled Bottom Sheet#
<BottomSheet
visible={visible}
onClose={() => setVisible(false)}
title="Custom Styled"
backgroundColor="#1F2937"
textColor="#F3F4F6"
borderRadius={32}
showHeaderBorder={false}
>
<View style={{ padding: 20 }}>
<Text style={{ color: '#F3F4F6' }}>Dark themed sheet with large corners</Text>
</View>
</BottomSheet>
<BottomSheet
visible={visible}
onClose={() => setVisible(false)}
title="Custom Styled"
backgroundColor="#1F2937"
textColor="#F3F4F6"
borderRadius={32}
showHeaderBorder={false}
>
<View style={{ padding: 20 }}>
<Text style={{ color: '#F3F4F6' }}>Dark themed sheet with large corners</Text>
</View>
</BottomSheet>
Extreme Header Positioning#
<BottomSheet
visible={visible}
onClose={() => setVisible(false)}
title="Settings"
closePosition="left"
titlePosition="right"
>
<Text>Close button is on the extreme left, title on the right.</Text>
</BottomSheet>
<BottomSheet
visible={visible}
onClose={() => setVisible(false)}
title="Settings"
closePosition="left"
titlePosition="right"
>
<Text>Close button is on the extreme left, title on the right.</Text>
</BottomSheet>
Notes#
- Entire surface is swipeable for high-responsiveness
- Supports gestures for dismissing
- Handle indicator helps users understand they can drag
- Works seamlessly with keyboard
- Fully customizable header slots (left, center, right)