# P drawer 15

> Chat composer pinned above the mobile keyboard

A shadcn/ui block from the [@coss](https://coss.com/ui) registry, listed on [shadcn.exchange](https://shadcn.exchange/r/coss/p-drawer-15).

- Page, with a live preview: https://shadcn.exchange/r/coss/p-drawer-15
- Screenshot: https://abzjhwgwpdpz7ua5.public.blob.vercel-storage.com/shots/coss/p-drawer-15-light-e6c366e607f56abc.png
- Registry item: https://coss.com/ui/r/p-drawer-15.json
- Categories: drawer, composer
- Listed: 2026-10-13, source last changed 2026-10-13

## Install

```bash
npx shadcn@latest add https://coss.com/ui/r/p-drawer-15.json
```

Run it in a project that has shadcn/ui set up. It adds the files below and installs what they depend on.

## Dependencies

- npm packages: `lucide-react`
- Registry items: `@coss/button`, `@coss/composer`, `@coss/drawer`

## Files

### `registry/default/particles/p-drawer-15.tsx`

```tsx
"use client";

import { ArrowUpIcon } from "lucide-react";
import { useState } from "react";
import { Button } from "@/registry/default/ui/button";
import {
  Composer,
  ComposerActionGroup,
  ComposerActions,
  ComposerInput,
  ComposerItem,
  type ComposerItemValue,
  ComposerList,
  ComposerPopup,
  ComposerSubmit,
  type ComposerValue,
} from "@/registry/default/ui/composer";
import {
  Drawer,
  DrawerHeader,
  DrawerPanel,
  DrawerPopup,
  DrawerTitle,
  DrawerTrigger,
} from "@/registry/default/ui/drawer";

const blocks = Array.from({ length: 32 }, (_, index) => `block-${index}`);

const people = [
  { id: "alex", label: "Alex Morgan" },
  { id: "sam", label: "Sam Rivera" },
];

const actions = [
  { id: "summarize", label: "Summarize", type: "action" as const },
  { id: "rewrite", label: "Rewrite", type: "action" as const },
];

export default function Particle() {
  const [value, setValue] = useState<ComposerValue>([]);

  return (
    <Drawer>
      <DrawerTrigger render={<Button variant="outline" />}>
        Open chat drawer
      </DrawerTrigger>
      <DrawerPopup className="[--drawer-height:calc(100dvh-3rem)]" showBar>
        <DrawerHeader>
          <DrawerTitle>Chat</DrawerTitle>
        </DrawerHeader>
        <div className="min-h-0 flex-1">
          <DrawerPanel>
            <div aria-hidden="true" className="flex flex-col gap-2">
              {blocks.map((key) => (
                <div className="h-12 shrink-0 rounded-xl bg-muted" key={key} />
              ))}
            </div>
          </DrawerPanel>
        </div>
        <Composer
          className="mx-3 mb-3"
          value={value}
          onValueChange={setValue}
          onSubmit={() => setValue([])}
          triggers={[
            { character: "@", items: people },
            { character: "/", items: actions },
          ]}
        >
          <ComposerInput aria-label="Message" placeholder="Write a message…" />
          <ComposerPopup>
            <ComposerList>
              {(item: ComposerItemValue) => (
                <ComposerItem key={item.id} value={item}>
                  {item.label}
                </ComposerItem>
              )}
            </ComposerList>
          </ComposerPopup>
          <ComposerActions>
            <ComposerActionGroup align="end">
              <ComposerSubmit
                render={
                  <Button aria-label="Send message" size="icon">
                    <ArrowUpIcon aria-hidden="true" />
                  </Button>
                }
              />
            </ComposerActionGroup>
          </ComposerActions>
        </Composer>
      </DrawerPopup>
    </Drawer>
  );
}
```
