ActionSheet
Action sheet with a list of actions, powered by @gorhom/bottom-sheet.
import { ActionSheet } from "@/components/ui/action-sheet";
import { useRef } from "react";
import GorhomBottomSheet from "@gorhom/bottom-sheet";
export function MyScreen() {
const sheetRef = useRef<GorhomBottomSheet>(null);
return (
<>
<Button onPress={() => sheetRef.current?.expand()}>
Show Actions
</Button>
<ActionSheet
ref={sheetRef}
title="Choose an action"
actions={[
{ label: "Share", onPress: () => console.log("Share") },
{ label: "Edit", onPress: () => console.log("Edit") },
{ label: "Delete", onPress: () => console.log("Delete"), destructive: true },
]}
onCancel={() => sheetRef.current?.close()}
/>
</>
);
}Installation
npx @aniui/cli add action-sheetThis component requires additional dependencies:
npx expo install @gorhom/bottom-sheet react-native-gesture-handler react-native-reanimatedYou also need to wrap your app with GestureHandlerRootView from react-native-gesture-handler.
Usage
app/index.tsx
import { ActionSheet } from "@/components/ui/action-sheet";
import { useRef } from "react";
import GorhomBottomSheet from "@gorhom/bottom-sheet";
export function MyScreen() {
const sheetRef = useRef<GorhomBottomSheet>(null);
return (
<>
<Button onPress={() => sheetRef.current?.expand()}>
Show Actions
</Button>
<ActionSheet
ref={sheetRef}
title="Choose an action"
actions={[
{ label: "Share", onPress: () => console.log("Share") },
{ label: "Edit", onPress: () => console.log("Edit") },
{ label: "Delete", onPress: () => console.log("Delete"), destructive: true },
]}
onCancel={() => sheetRef.current?.close()}
/>
</>
);
}Props
PropTypeDefault
titlestring—actionsActionSheetAction[]requiredonCancel() => void—classNamestring—ActionSheetAction
PropTypeDefault
labelstringrequiredonPress() => voidrequireddestructivebooleanfalseUse a ref to control the sheet imperatively. Call expand() to open and close() to dismiss.
Source
components/ui/action-sheet.tsx
import React, { forwardRef, useCallback } from "react";
import { View, Pressable, Text } from "react-native";
import GorhomBottomSheet, { BottomSheetBackdrop, BottomSheetView } from "@gorhom/bottom-sheet";
import { cn } from "@/lib/utils";
export interface ActionSheetAction {
label: string;
onPress: () => void;
destructive?: boolean;
}
export interface ActionSheetProps {
className?: string;
title?: string;
actions: ActionSheetAction[];
onCancel?: () => void;
}
export const ActionSheet = forwardRef<GorhomBottomSheet, ActionSheetProps>(
({ className, title, actions, onCancel }, ref) => {
const renderBackdrop = useCallback(
(backdropProps: React.ComponentProps<typeof BottomSheetBackdrop>) => (
<BottomSheetBackdrop {...backdropProps} disappearsOnIndex={-1} appearsOnIndex={0} opacity={0.5} />
),
[]
);
return (
<GorhomBottomSheet
ref={ref}
index={-1}
enableDynamicSizing
enablePanDownToClose
backdropComponent={renderBackdrop}
backgroundStyle={{ backgroundColor: "hsl(0 0% 100%)" }}
handleIndicatorStyle={{ backgroundColor: "hsl(240 3.8% 46.1%)" }}
>
<BottomSheetView>
<View className={cn("pb-8 px-4", className)}>
{title && <Text className="text-sm text-muted-foreground text-center py-3">{title}</Text>}
{actions.map((action, i) => (
<Pressable
key={i}
className="py-4 items-center border-b border-border min-h-12"
onPress={action.onPress}
accessible={true}
accessibilityRole="button"
>
<Text className={cn("text-base font-medium", action.destructive ? "text-destructive" : "text-foreground")}>
{action.label}
</Text>
</Pressable>
))}
{onCancel && (
<Pressable className="py-4 items-center mt-2 min-h-12" onPress={onCancel} accessible={true} accessibilityRole="button">
<Text className="text-base font-semibold text-muted-foreground">Cancel</Text>
</Pressable>
)}
</View>
</BottomSheetView>
</GorhomBottomSheet>
);
}
);
ActionSheet.displayName = "ActionSheet";