AniUI

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-sheet

This component requires additional dependencies:

npx expo install @gorhom/bottom-sheet react-native-gesture-handler react-native-reanimated

You 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
title
string
actions
ActionSheetAction[]
required
onCancel
() => void
className
string

ActionSheetAction

PropTypeDefault
label
string
required
onPress
() => void
required
destructive
boolean
false

Use 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";