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

# Drawer

> A panel that slides in from the edge of the viewport, built from DrawerTrigger, DrawerContent, DrawerHeader, DrawerTitle, DrawerDescription and DrawerFooter.

```tsx theme={null}
import {
  Drawer,
  DrawerClose,
  DrawerContent,
  DrawerDescription,
  DrawerFooter,
  DrawerHeader,
  DrawerOverlay,
  DrawerTitle,
  DrawerTrigger,
} from "@fanvue/ui";
import type {
  DrawerCloseProps,
  DrawerContentProps,
  DrawerDescriptionProps,
  DrawerFooterProps,
  DrawerHeaderProps,
  DrawerOverlayProps,
  DrawerPosition,
  DrawerProps,
  DrawerSize,
  DrawerTitleProps,
  DrawerTriggerProps,
  DrawerVariant,
} from "@fanvue/ui";
```

## Examples

## Default

<Frame>
  <iframe src={"https://main--697a1b6dd4dad73ee9c0e5f5.chromatic.com/iframe.html?id=components-drawer--default&viewMode=story&shortcuts=false&singleStory=true&globals=theme:light"} width="100%" height="460" style={{border: "none", borderRadius: "8px"}} loading="lazy" title="Drawer — Default" />
</Frame>

```tsx theme={null}
import {
  Button,
  Drawer,
  DrawerClose,
  DrawerContent,
  DrawerDescription,
  DrawerFooter,
  DrawerHeader,
  DrawerTitle,
  DrawerTrigger,
} from "@fanvue/ui";

<Drawer>
  <DrawerTrigger asChild>
    <Button>Open Drawer</Button>
  </DrawerTrigger>
  <DrawerContent position="right" size="sm" overlay>
    <DrawerHeader>
      <DrawerTitle>Drawer Title</DrawerTitle>
      <DrawerDescription>
        This is a default drawer that slides in from the right.
      </DrawerDescription>
    </DrawerHeader>
    <div className="flex-1 overflow-y-auto p-4">
      <p>Drawer content goes here.</p>
    </div>
    <DrawerFooter>
      <DrawerClose asChild>
        <Button variant="secondary">Close</Button>
      </DrawerClose>
    </DrawerFooter>
  </DrawerContent>
</Drawer>
```

## Without Overlay

<Frame>
  <iframe src={"https://main--697a1b6dd4dad73ee9c0e5f5.chromatic.com/iframe.html?id=components-drawer--without-overlay&viewMode=story&shortcuts=false&singleStory=true&globals=theme:light"} width="100%" height="460" style={{border: "none", borderRadius: "8px"}} loading="lazy" title="Drawer — Without Overlay" />
</Frame>

```tsx theme={null}
import {
  Button,
  Drawer,
  DrawerClose,
  DrawerContent,
  DrawerDescription,
  DrawerFooter,
  DrawerHeader,
  DrawerTitle,
  DrawerTrigger,
} from "@fanvue/ui";

<Drawer overlay={false}>
  <DrawerTrigger asChild>
    <Button>Open Without Overlay</Button>
  </DrawerTrigger>
  <DrawerContent position="right" size="sm" overlay={false}>
    <DrawerHeader>
      <DrawerTitle>No Overlay</DrawerTitle>
      <DrawerDescription>This drawer has no backdrop overlay behind it.</DrawerDescription>
    </DrawerHeader>
    <div className="flex-1 overflow-y-auto p-4">
      <p>The page behind remains fully visible.</p>
    </div>
    <DrawerFooter>
      <DrawerClose asChild>
        <Button variant="secondary">Close</Button>
      </DrawerClose>
    </DrawerFooter>
  </DrawerContent>
</Drawer>
```

## Left

<Frame>
  <iframe src={"https://main--697a1b6dd4dad73ee9c0e5f5.chromatic.com/iframe.html?id=components-drawer--left&viewMode=story&shortcuts=false&singleStory=true&globals=theme:light"} width="100%" height="460" style={{border: "none", borderRadius: "8px"}} loading="lazy" title="Drawer — Left" />
</Frame>

```tsx theme={null}
import {
  Button,
  Drawer,
  DrawerClose,
  DrawerContent,
  DrawerDescription,
  DrawerFooter,
  DrawerHeader,
  DrawerTitle,
  DrawerTrigger,
} from "@fanvue/ui";

<Drawer>
  <DrawerTrigger asChild>
    <Button>Open Left Drawer</Button>
  </DrawerTrigger>
  <DrawerContent position="left" size="sm" overlay>
    <DrawerHeader>
      <DrawerTitle>Left Drawer</DrawerTitle>
      <DrawerDescription>This drawer slides in from the left.</DrawerDescription>
    </DrawerHeader>
    <div className="flex-1 overflow-y-auto p-4">
      <p>Navigation or sidebar content.</p>
    </div>
    <DrawerFooter>
      <DrawerClose asChild>
        <Button variant="secondary">Close</Button>
      </DrawerClose>
    </DrawerFooter>
  </DrawerContent>
</Drawer>
```

## Controlled

<Frame>
  <iframe src={"https://main--697a1b6dd4dad73ee9c0e5f5.chromatic.com/iframe.html?id=components-drawer--controlled&viewMode=story&shortcuts=false&singleStory=true&globals=theme:light"} width="100%" height="460" style={{border: "none", borderRadius: "8px"}} loading="lazy" title="Drawer — Controlled" />
</Frame>

```tsx theme={null}
import { useState } from "react";
import {
  Button,
  Drawer,
  DrawerContent,
  DrawerDescription,
  DrawerFooter,
  DrawerHeader,
  DrawerTitle,
} from "@fanvue/ui";

function Example() {
  const [open, setOpen] = useState(false);
  return (
    <div className="flex items-center gap-4">
      <Button onClick={() => setOpen(true)}>Open Controlled Drawer</Button>
      <span className="typography-description-12px-regular text-content-secondary">
        {open ? "Open" : "Closed"}
      </span>
      <Drawer open={open} onOpenChange={setOpen}>
        <DrawerContent position="right" size="sm" overlay>
          <DrawerHeader>
            <DrawerTitle>Controlled Drawer</DrawerTitle>
            <DrawerDescription>This drawer is controlled via external state.</DrawerDescription>
          </DrawerHeader>
          <div className="flex-1 overflow-y-auto p-4">
            <p>The open state is managed by the parent component.</p>
          </div>
          <DrawerFooter>
            <Button variant="secondary" onClick={() => setOpen(false)}>
              Close
            </Button>
          </DrawerFooter>
        </DrawerContent>
      </Drawer>
    </div>
  );
}
```

## Top

<Frame>
  <iframe src={"https://main--697a1b6dd4dad73ee9c0e5f5.chromatic.com/iframe.html?id=components-drawer--top&viewMode=story&shortcuts=false&singleStory=true&globals=theme:light"} width="100%" height="460" style={{border: "none", borderRadius: "8px"}} loading="lazy" title="Drawer — Top" />
</Frame>

```tsx theme={null}
import {
  Button,
  Drawer,
  DrawerClose,
  DrawerContent,
  DrawerDescription,
  DrawerFooter,
  DrawerHeader,
  DrawerTitle,
  DrawerTrigger,
} from "@fanvue/ui";

<Drawer>
  <DrawerTrigger asChild>
    <Button>Open Top Drawer</Button>
  </DrawerTrigger>
  <DrawerContent position="top" size="sm" overlay>
    <DrawerHeader>
      <DrawerTitle>Top Drawer</DrawerTitle>
      <DrawerDescription>This drawer slides in from the top.</DrawerDescription>
    </DrawerHeader>
    <div className="p-4">
      <p>Notification or banner content.</p>
    </div>
    <DrawerFooter>
      <DrawerClose asChild>
        <Button variant="secondary">Close</Button>
      </DrawerClose>
    </DrawerFooter>
  </DrawerContent>
</Drawer>
```

## Props

## Drawer

Root component that manages open/close state for a drawer. Wraps Radix Dialog.Root.

<ParamField path="overlay" type="boolean" default="true">
  Whether the default `DrawerOverlay` is rendered. When `false`, `modal` is automatically set to `false` as well (unless explicitly overridden) so focus-trap and scroll-lock are disabled.
</ParamField>

## DrawerClose

Closes the drawer when clicked. Can be placed anywhere inside the drawer.

A direct re-export of the Radix `DialogPrimitive.Close` primitive. It accepts all of that primitive's props, unchanged.

## DrawerContent

The panel that slides in from the chosen edge. Renders inside a portal with an overlay backdrop by default.

Includes focus-trap, `aria-describedby`, and Escape-to-close from Radix Dialog.

<ParamField path="asChild" type="boolean" />

<ParamField path="overlay" type="boolean" default="true">
  Whether to render the default `DrawerOverlay` behind the content. Set to `false` to provide your own overlay or omit it entirely.

  Prefer setting `overlay` on the `Drawer` root instead so that `modal` is also adjusted automatically.
</ParamField>

<ParamField path="overlayProps" type="DrawerOverlayProps">
  Props forwarded to the default `DrawerOverlay` when `overlay` is `true`.
</ParamField>

<ParamField path="position" type="&#x22;top&#x22; | &#x22;bottom&#x22; | &#x22;left&#x22; | &#x22;right&#x22;" default="right">
  The edge from which the drawer slides in.

  Named `position` (rather than `side`) to avoid confusion with the CSS `side` concept used by Radix Popover/Tooltip and to better convey the spatial relationship of the drawer to the viewport.
</ParamField>

<ParamField path="size" type="&#x22;md&#x22; | &#x22;sm&#x22; | &#x22;lg&#x22; | &#x22;full&#x22;" default="sm">
  Controls the maximum extent of the drawer panel. For left/right drawers this sets `max-width`; for top/bottom it sets `max-height`.
</ParamField>

<ParamField path="variant" type="&#x22;menu&#x22; | &#x22;sheet&#x22; | &#x22;panel&#x22;" default="panel">
  Visual treatment of the panel. Use `"sheet"` (with `position="bottom"`) for a bottom sheet with the modal surface treatment, or `"menu"` for a floating inset menu carrying the dropdown surface.
</ParamField>

## DrawerDescription

An accessible description for the drawer, providing supplementary context.

<ParamField path="asChild" type="boolean" />

## DrawerFooter

A semantic footer area for the drawer, typically containing action buttons.

Takes no props of its own. Accepts all standard `div` attributes, including `className`.

## DrawerHeader

A semantic header area for the drawer, typically containing a title and description. Renders a built-in close button by default.

<ParamField path="closeLabel" type="string" default="Close drawer">
  Accessible label for the close button.
</ParamField>

<ParamField path="showClose" type="boolean" default="true">
  Whether to show a built-in close (X) button.
</ParamField>

## DrawerOverlay

A translucent backdrop rendered behind the drawer content. Clicking the overlay closes the drawer by default.

<ParamField path="asChild" type="boolean" />

## DrawerTitle

An accessible title for the drawer. Required for screen readers.

<ParamField path="asChild" type="boolean" />

## DrawerTrigger

The element that opens the drawer when clicked.

On touch / pen, a press-and-release that crosses a small movement threshold is treated as a drag and the resulting synthetic click is suppressed — defends against Android Chrome opening the drawer on a scroll-drag-end.

<ParamField path="asChild" type="boolean" />

## Exported types

Also exported from `@fanvue/ui`: `DrawerCloseProps`, `DrawerContentProps`, `DrawerDescriptionProps`, `DrawerFooterProps`, `DrawerHeaderProps`, `DrawerOverlayProps`, `DrawerPosition`, `DrawerProps`, `DrawerSize`, `DrawerTitleProps`, `DrawerTriggerProps`, `DrawerVariant`.

***

**Setup:** [Installation](/docs/ui/installation) · [Theming](/docs/ui/theming)
