> Leaf UI 0.6.0 · Package: @ifhover/leaf-ui · Source: b30c3d3a8fa9c5e15d0d0522cebfbd33f60c6b06
> Browser documentation: https://ifhover.github.io/leaf-ui/v/0.6.0/en/components/drawer.html

> For AI agents: the complete documentation index is available at https://ifhover.github.io/leaf-ui/v/0.6.0/en/llms.txt, the full documentation bundle is available at https://ifhover.github.io/leaf-ui/v/0.6.0/en/llms-full.txt.

# Drawer

Open content from a page edge to view details or complete actions.

## Basic usage


leftrighttopbottom

basic.tsx

Copy code

```tsx lineNumbers file="../../../src/examples/en/drawer/basic.tsx"
import { Button, Drawer, Flex, Form, FormField, Input, Select, Space } from '@ifhover/leaf-ui';

import { useState } from 'react';

export function DrawerBasic() {
  const [placement, setPlacement] = useState<'left' | 'right' | 'top' | 'bottom'>('right');
  const [open, setOpen] = useState(false);
  return (
    <Space direction="vertical" align="stretch">
      <Flex gap="md" align="center" wrap justify="center">
        {(['left', 'right', 'top', 'bottom'] as const).map((side) => (
          <Button
            key={side}
            variant="outline"
            onClick={() => {
              setPlacement(side);
              setOpen(true);
            }}
          >
            {side}
          </Button>
        ))}
      </Flex>
      <Drawer
        open={open}
        placement={placement}
        title="Project settings"
        onClose={() => setOpen(false)}
        footer={
          <>
            <Button variant="outline" onClick={() => setOpen(false)}>
              Cancel
            </Button>
            <Button type="submit" form="drawer-project">
              Save
            </Button>
          </>
        }
      >
        <Form
          id="drawer-project"
          onSubmit={(event) => {
            event.preventDefault();
            setOpen(false);
          }}
        >
          <FormField label="Project name" required>
            <Input name="name" defaultValue="Leaf Garden" />
          </FormField>
          <FormField label="Project type">
            <Select
              name="type"
              defaultValue="design"
              options={[
                { value: 'design', label: 'Design' },
                { value: 'development', label: 'Development' },
              ]}
            />
          </FormField>
        </Form>
      </Drawer>
    </Space>
  );
}
```

Expand code

## Resize and nested push


Resizable workspace

capabilities.tsx

Copy code

```tsx lineNumbers file="../../../src/examples/drawer/capabilities.tsx"
import { Button, Drawer, Input, Space } from '@ifhover/leaf-ui';

import { useState } from 'react';

export function Capabilities() {
  const [open, setOpen] = useState(false),
    [child, setChild] = useState(false);
  return (
    <>
      <Button onClick={() => setOpen(true)}>
        {'Resizable workspace'}
      </Button>
      <Drawer
        title={'Workspace'}
        open={open}
        onClose={() => setOpen(false)}
        resizable
        minSize={260}
        maxSize={640}
      >
        <Space direction="vertical">
          <Input aria-label="Project" />
          <Button onClick={() => setChild(true)}>{'Open details'}</Button>
        </Space>
        <Drawer
          open={child}
          onClose={() => setChild(false)}
          title={'Details'}
          width={300}
          push={120}
        >
          Details
        </Drawer>
      </Drawer>
    </>
  );
}
```

Expand code

## Notification preferences

Separate the heading, settings and footer actions.


Notification preferences

sections.tsx

Copy code

```tsx lineNumbers file="../../../src/examples/drawer/sections.tsx"
import { Alert, Button, Drawer, RadioGroup, Space } from '@ifhover/leaf-ui';

import { Bell } from 'lucide-react';

import { useState } from 'react';

export function DrawerSections() {
  
  const [open, setOpen] = useState(false);
  const [frequency, setFrequency] = useState('weekly');
  return (
    <>
      <Button variant="outline" startIcon={<Bell />} onClick={() => setOpen(true)}>
        {'Notification preferences'}
      </Button>
      <Drawer
        open={open}
        width={440}
        title={'Notification preferences'}
        description={'Choose the right update frequency for you.'}
        icon={<Bell />}
        onClose={() => setOpen(false)}
        footer={
          <>
            <Button variant="outline" onClick={() => setOpen(false)}>
              {'Cancel'}
            </Button>
            <Button onClick={() => setOpen(false)}>{'Save'}</Button>
          </>
        }
      >
        <Space direction="vertical" align="stretch" size={20}>
          <RadioGroup
            variant="list"
            label={'Activity summary'}
            value={frequency}
            onChange={(event) => setFrequency(event.target.value)}
            options={[
              {
                value: 'daily',
                label: 'Daily',
                description: 'A daily team activity digest',
              },
              {
                value: 'weekly',
                label: 'Weekly',
                description: 'A summary every Monday',
              },
              {
                value: 'off',
                label: 'No summary',
                description: 'Receive only important updates',
              },
            ]}
          />
          <Alert
            type="info"
            title={'Important alerts stay enabled'}
            description={'Security events and actions requiring your attention are always delivered.'}
          />
        </Space>
      </Drawer>
    </>
  );
}
```

Expand code

## Drawer API

| Property         | Type                                                                       | Default   | Description                                                             |
| ---------------- | -------------------------------------------------------------------------- | --------- | ----------------------------------------------------------------------- |
| `initialFocus`   | `RefObject<HTMLElement \| null> \| (() => HTMLElement \| null)`            | —         | Specify initial focus after opening.                                    |
| `returnFocus`    | `boolean \| RefObject<HTMLElement \| null> \| (() => HTMLElement \| null)` | —         | Restore focus on close; specify a destination or use false.             |
| `open`           | `boolean`                                                                  | Required  | Required. Whether the drawer is open                                    |
| `title`          | `ReactNode`                                                                | —         | Title                                                                   |
| `description`    | `ReactNode`                                                                | —         | Additional description.                                                 |
| `icon`           | `ReactNode`                                                                | —         | Decorative icon to the left of the heading.                             |
| `divided`        | `boolean`                                                                  | `true`    | Separate the heading, content and footer with subtle borders.           |
| `footer`         | `ReactNode`                                                                | —         | Footer content                                                          |
| `extra`          | `ReactNode`                                                                | —         | Actions beside the title                                                |
| `placement`      | `'left' \| 'right' \| 'top' \| 'bottom'`                                   | `'right'` | Opening edge                                                            |
| `width`          | `number \| string`                                                         | `380`     | Width for left and right drawers                                        |
| `height`         | `number \| string`                                                         | `300`     | Height for top and bottom drawers                                       |
| `closable`       | `boolean`                                                                  | `true`    | Close button / backdrop click / Escape                                  |
| `maskClosable`   | `boolean`                                                                  | `true`    | Close button / backdrop click / Escape                                  |
| `keyboard`       | `boolean`                                                                  | `true`    | Close button / backdrop click / Escape                                  |
| `onClose`        | `() => void`                                                               | —         | Close request; update open in application state                         |
| `afterClose`     | `() => void`                                                               | —         | Called after the closing transition                                     |
| `forceRender`    | `boolean`                                                                  | `false`   | Mount before opening and keep hidden while closed.                      |
| `destroyOnClose` | `boolean`                                                                  | `false`   | Unmount content after the closing transition; preserved by default.     |
| `preserve`       | `boolean`                                                                  | —         | Explicitly preserve closed content; overrides destroyOnClose.           |
| `container`      | `Element \| DocumentFragment \| (() => Element \| DocumentFragment)`       | —         | Custom portal or scroll container.                                      |
| `push`           | `boolean \| number`                                                        | `false`   | Push the parent overlay when a nested drawer opens; accepts a distance. |
| `resizable`      | `boolean`                                                                  | `false`   | Allow resizing by dragging or arrow keys.                               |
| `minSize`        | `number`                                                                   | `240`     | Minimum size in pixels.                                                 |
| `maxSize`        | `number`                                                                   | `900`     | Maximum size in pixels.                                                 |
| `onResize`       | `(size: number) => void`                                                   | —         | Called while resizing.                                                  |

## Types

Import the component props and item types when preparing your own values.

```ts
import type { DrawerProps } from '@ifhover/leaf-ui';
```

## Usage notes

Place actions in footer. A submit button can use its form attribute to target a form inside the drawer. Provide aria-label if there is no title. Nested dialogs are supported, and focus returns to the opener after closing.

## Surfaces and rich content

Use `description` and `icon` to explain the current task. The heading and muted footer have subtle dividers by default; `divided={false}` groups content with spacing.
