> ## Documentation Index
> Fetch the complete documentation index at: https://anvil.servicetitan.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Bottom Sheet – Code

> The BottomSheet provides a bottom-anchored modal surface for general content.

<Tabs>
  <Tab title="Implementation">
    ```tsx theme={null}
    import { BottomSheet, Button } from "@servicetitan/anvil2-rn";

    function App() {
      return (
        <BottomSheet
          title="Quick actions"
          content="Review these actions before you continue."
          trigger={<Button label="Open sheet" variant="secondary" />}
        />
      );
    }
    ```

    ## Common Examples

    To use the `BottomSheet`, pass the required `title` and `content`. Open it with an Anvil2 RN `Button` through `trigger`, or control it with `isOpen` and `onOpenChange`.

    ```tsx theme={null}
    import { BottomSheet, Button } from "@servicetitan/anvil2-rn";

    function ExampleComponent() {
      return (
        <BottomSheet
          title="Filters"
          trigger={<Button label="Open filters" />}
          content={<FilterForm />}
        />
      );
    }
    ```

    ### Body content

    Unlike `Dialog`, the sheet's `content` is a general body region for forms, lists, and composed layouts. A plain string still renders in the sheet's body typography. The header stays pinned while the body scrolls.

    ### Subheader

    Pass a short `subheader` for context beneath the title.

    ```tsx theme={null}
    <BottomSheet
      title="Job #48213"
      subheader="Scheduled for tomorrow at 9:00 AM"
      content="Review the job details before confirming the appointment."
      trigger={<Button label="Open sheet" variant="secondary" />}
    />
    ```

    ### Open state

    Omit `isOpen` for an uncontrolled sheet. Seed it with `defaultOpen`. When you pass `isOpen`, `onOpenChange` is required so the header close, scrim, Android back, and drag-to-dismiss can request a close.

    ```tsx theme={null}
    const [isOpen, setOpen] = useState(false);

    <BottomSheet
      title="Filters"
      content={<FilterForm />}
      isOpen={isOpen}
      onOpenChange={setOpen}
    />
    ```

    Set `isDismissable={false}` to keep the scrim and Android back from closing the sheet. The header close still dismisses when `showCloseButton` is true.

    ## Accessibility

    * The required `title` is a heading that names the modal. The sheet sets `accessibilityViewIsModal`.
    * The header close control is a button named `"Close"` (English until the kit gains i18n).
    * Drag down on the handle, tap the scrim, or use Android back to dismiss when `isDismissable` is true.
    * Reduce motion skips the slide animation.
  </Tab>

  <Tab title="BottomSheet Props">
    ```tsx theme={null}
    <BottomSheet
      title="Filters"
      subheader="Narrow your results"
      trigger={<Button label="Open filters" />}
      content={<FilterForm />}
      showCloseButton
    />
    ```

    ## `BottomSheet` Props

    The `BottomSheet` accepts the following props. It does not forward remaining React Native `Modal` or `View` props. Open state is a discriminated union: pass `isOpen` with `onOpenChange`, or omit `isOpen` for the uncontrolled form.

    <ParamField path="content" type="ReactNode" required>
      General body content, including forms, lists, and composed layout.
    </ParamField>

    <ParamField path="title" type="string" required>
      Accessible title rendered in the header.
    </ParamField>

    <ParamField path="analyticsId" type="string">
      Opt-in telemetry id. When set under `Anvil2RNTelemetryProvider`, the
      header close, scrim, and Android back emit a `dismiss` event.
    </ParamField>

    <ParamField path="defaultOpen" type="boolean">
      Whether the sheet starts open when uncontrolled. Unavailable when
      `isOpen` is set.
    </ParamField>

    <ParamField path="isDismissable" type="boolean" default="true">
      Whether tapping the scrim or using Android back closes the sheet.
    </ParamField>

    <ParamField path="isOpen" type="boolean">
      Controlled open state. Pair with `onOpenChange`.
    </ParamField>

    <ParamField path="onOpenChange" type="(isOpen: boolean) => void">
      Called when the open state changes. Required when `isOpen` is set.
    </ParamField>

    <ParamField path="showCloseButton" type="boolean" default="true">
      Shows the header close button.
    </ParamField>

    <ParamField path="subheader" type="string">
      Short secondary line beneath the title.
    </ParamField>

    <ParamField path="testID" type="string">
      Test hook forwarded to the sheet surface.
    </ParamField>

    <ParamField path="trigger" type="ReactElement<ButtonProps>">
      Anvil2 RN `Button` that opens the sheet. Omit for controlled state.
    </ParamField>
  </Tab>
</Tabs>
