Skip to main content

Bottom Sheet

Bottom sheets are surfaces containing supplementary content, anchored to the bottom of the screen. They can provide users with quick access to contextual information, actions, or settings without interrupting their current workflow.

Loading...

The BottomSheet component accepts props such as isOpen - a shared value indicating whether the bottom sheet is open or closed, toggleSheet - a function to toggle the visibility of the bottom sheet, and an optional duration for animation.

Bottom Sheet
function BottomSheet({ isOpen, toggleSheet, duration = 500, children }) {
const height = useSharedValue(0);
const progress = useDerivedValue(() =>
withTiming(isOpen.value ? 0 : 1, { duration })
);

const sheetStyle = useAnimatedStyle(() => ({
transform: [{ translateY: progress.value * 2 * height.value }],
}));

const backdropStyle = useAnimatedStyle(() => ({
opacity: 1 - progress.value,
zIndex: isOpen.value
? 1
: withDelay(duration, withTiming(-1, { duration: 0 })),
}));

return (
<>
<Animated.View style={[sheetStyles.backdrop, backdropStyle]}>
<TouchableOpacity style={styles.flex} onPress={toggleSheet} />
</Animated.View>
<Animated.View
onLayout={(e) => {
height.value = e.nativeEvent.layout.height;
}}
style={[sheetStyles.sheet, sheetStyle]}>
{children}
</Animated.View>
</>
);
}

The height shared value is used to track the height of the bottom sheet, while the progress derived value interpolates between 0 and 1 based on the state of isOpen, controlling the animation of the bottom sheet.

  const height = useSharedValue(0);
const progress = useDerivedValue(() =>
withTiming(isOpen.value ? 0 : 1, { duration })
);

The useAnimatedStyle hook helps in creating animated styles based on shared values. These styles are then applied to BottomSheet to make it visually dynamic by adding backdrop and translating bottom sheet to the top.

  const sheetStyle = useAnimatedStyle(() => ({
transform: [{ translateY: progress.value * 2 * height.value }],
}));

const backdropStyle = useAnimatedStyle(() => ({
opacity: 1 - progress.value,
zIndex: isOpen.value
? 1
: withDelay(duration, withTiming(-1, { duration: 0 })),
}));