# BottomSheet (React Native)

> A panel that slides up from the bottom for secondary actions, a short form or details. Drag down, tap outside or press back to close.

GramproKit for React Native · Mobile · Beta · Source: https://kit.gramproindia.com/native/docs/bottom-sheet

> **Beta:** React Native support is in beta. APIs may change or break between prereleases (npm tag `native`).

_Interactive demo:_ [open the live example](https://kit.gramproindia.com/native/docs/bottom-sheet). The example's source:

```tsx
import { useState } from "react";
import { Text, TextInput } from "react-native";
import { Button } from "@/component-lib/button";
import { useKitTheme } from "@/component-lib/shared/native";
import { BottomSheet, BottomSheetClose } from "@/component-lib/bottom-sheet";
import { ListItem, List } from "@/component-lib/list-item";
import { Row, Section } from "./layout"; // Section and Row: page layout for the demo

export function BottomSheetDemo() {
  const { tokens } = useKitTheme();
  const [open, setOpen] = useState(false);
  const [last, setLast] = useState("nothing yet");
  const [note, setNote] = useState("");
  return (
    <Section title="BottomSheet">
      <Row>
        <BottomSheet
          trigger={<Button variant="outline">Share</Button>}
          title="Share invoice"
          description="Pick how to send INV-2041."
          footer={(close) => (
            <Button variant="secondary" onPress={close}>
              Cancel
            </Button>
          )}
        >
          {(close) => (
            <List style={{ marginHorizontal: -16 }}>
              {["Copy link", "WhatsApp", "Email", "Download PDF"].map((label) => (
                <ListItem
                  key={label}
                  title={label}
                  onPress={() => {
                    setLast(label);
                    close();
                  }}
                />
              ))}
            </List>
          )}
        </BottomSheet>
        <Button variant="outline" onPress={() => setOpen(true)}>
          Add note (controlled)
        </Button>
      </Row>
      <Text style={{ color: tokens.muted, fontSize: tokens.fontSize - 2 }}>Last action: {last}</Text>
      <BottomSheet
        open={open}
        onOpenChange={setOpen}
        title="Add a note"
        footer={
          <>
            <BottomSheetClose>
              <Button variant="ghost">Discard</Button>
            </BottomSheetClose>
            <Button
              onPress={() => {
                setLast(note ? `note "${note}"` : "empty note");
                setOpen(false);
              }}
            >
              Save
            </Button>
          </>
        }
      >
        <TextInput
          value={note}
          onChangeText={setNote}
          placeholder="Type a note; the sheet stays above the keyboard"
          placeholderTextColor={tokens.muted}
          multiline
          style={{
            minHeight: 96,
            borderWidth: 1,
            borderColor: tokens.borderControl,
            borderRadius: tokens.radius,
            padding: 12,
            color: tokens.fg,
            fontSize: tokens.fontSize,
            textAlignVertical: "top",
          }}
        />
      </BottomSheet>
    </Section>
  );
}
```

## Install

```bash
npx @grampro/kit@native add BottomSheet
```

## Usage

```tsx
import { BottomSheet } from "@/component-lib/bottom-sheet";

<BottomSheet
  trigger={<Button variant="outline">Share</Button>}
  title="Share invoice"
  footer={(close) => <Button onPress={close}>Done</Button>}
>
  <ListItem title="Copy link" onPress={copy} />
</BottomSheet>
```

## Props

### BottomSheetProps

| Prop | Type | Description |
|---|---|---|
| `open` | `boolean` |   |
| `defaultOpen` | `boolean` |   |
| `onOpenChange` | `(open: boolean) => void` |   |
| `trigger` | `ReactElement<{ onPress?(event: GestureResponderEvent): void }>` | Pressing it opens the sheet: a Button or any element taking `onPress`. |
| `title` | `ReactNode` | Heading, also the sheet's accessible name. |
| `description` | `ReactNode` |   |
| `footer` | `Renderable` | Sticky actions under the scrolling content. A function receives `close`. |
| `dismissible` | `boolean` | Tap outside, drag down and Android back close it. Default true. |
| `maxHeight` | `number` | Largest height as a fraction of the screen. Default 0.9. |
| `scrollable` | `boolean` | Content scrolls when taller than the sheet. Default true. |
| `onClosed` | `() => void` | After the exit animation. |
| `style` | `StyleProp<ViewStyle>` |   |
| `styles` | `Partial<{ body: StyleProp<ViewStyle>; footer: StyleProp<ViewStyle> }>` |   |
| `children` | `Renderable` | Content. A function receives `close`. |

## Notes

- Built on Kit's shared `Sheet`: clears the home indicator and stays above the keyboard.
- No gesture or animation library: core `Animated` and `PanResponder`.
- Mobile only: there is no web version of this component.
