# Drawer

Import: `import { Drawer } from '@neo4j-ndl/react'`

## Props

### Drawer

| Prop | Type | Required | Default | Description |
|------|------|----------|---------|-------------|
| `ariaLabel` | `string` |  |  | The aria-label to apply to the drawer. Required for accessibility when type is "modal" or "overlay". |
| `as` | `ElementType<any, keyof IntrinsicElements>` |  |  | An override of the default HTML tag of the root of the component. Can also be another React component. |
| `children` | `ReactNode` | ✅ |  | The content to display within the drawer. |
| `closeOnClickOutside` | `boolean` |  | `false` | When type is "overlay", whether clicking outside the drawer closes it. Should be set to true for overlay drawers. - When type is "overlay" or "modal", this defaults to false. - When type is "push", no effect. |
| `closeOnEscape` | `boolean` |  | `type === 'modal' ? true : false` | Whether pressing Escape closes the drawer. Should be set to true for overlay drawers. - When type is "modal", this defaults to true. - When type is "overlay", this defaults to false. - When type is "push", no effect. |
| `closeOnFocusOut` | `boolean` |  |  | @deprecated overlay are now focus trapped by default, this prop has no effect anymore. |
| `isCloseable` | `boolean` |  | `true` | Whether a close button (X) is displayed in the drawer. |
| `isExpanded` | `boolean` | ✅ |  | Controls whether the drawer is open (expanded) or closed (collapsed). |
| `isPortaled` | `boolean` |  | `false` | Whether to portal the content. Only applies when type is "overlay". Type "modal" is always portaled. |
| `isResizeable` | `boolean` |  | `false` | Enables horizontal resizing of the drawer, by default it is not resizable. |
| `onExpandedChange` | `((expanded: boolean) => void)` |  |  | Callback fired when the drawer's expanded state changes (close button, Escape, click outside, or programmatic change). |
| `portalProps` | `FloatingPortalProps` |  | `{}` | Props to pass to the portal from @floating-ui /react FloatingPortal Only applies when type is "overlay" and isPortaled is true, or if type is "modal". @see https://floating-ui.com/docs/floatingportal |
| `position` | `'left' \| 'right'` |  | `left` | Position where the drawer appears on screen. By default, it appears from the left. |
| `ref` | `any` |  |  | A ref to apply to the root element. |
| `resizeableProps` | `ResizableProps` |  |  | To use this prop the isResizeable prop must be set to true. For overriding the third party library props: https://github.com/bokuweb/re-resizable The property enable has default values set for bottom, bottomLeft etc based on the position prop. |
| `type` | `'modal' \| 'overlay' \| 'push'` |  | `overlay` | How the drawer affects the layout of sibling content. By default, it overlays content. |

Where `ResizableProps` is the props for the `re-resizable` library. For more information, see the [re-resizable documentation](https://github.com/bokuweb/re-resizable).

Where `FloatingPortalProps` is the props for the `@floating-ui/react` library. For more information, see the [FloatingPortal documentation](https://floating-ui.com/docs/floatingportal).

### Drawer.Actions

| Prop | Type | Required | Default | Description |
|------|------|----------|---------|-------------|
| `children` | `ReactNode` | ✅ |  |  |

### Drawer.Body

| Prop | Type | Required | Default | Description |
|------|------|----------|---------|-------------|
| `children` | `ReactNode` | ✅ |  |  |

### Drawer.Header

| Prop | Type | Required | Default | Description |
|------|------|----------|---------|-------------|
| `children` | `ReactNode` | ✅ |  |  |

## Accessibility

## Implementation guidelines

A button that expands a Drawer should have `'aria-expanded'` set to whether the Drawer is expanded or not, following the [disclosure pattern]([https://www.w3.org/WAI/ARIA/apg/patterns/disclosure/](https://www.w3.org/WAI/ARIA/apg/patterns/disclosure/)).
A drawer of type "overlay" should set the props `closeOnClickOutside` and `closeOnFocusOut` to true. This ensures that it doesn't hide focus of interactive elements on the screen (WCAG 2.4.11). closeOnEscape is not strictly needed, but is recommended.
Drawers of type "overlay" or "modal" implement the dialog pattern, meaning they need to be labelled to be accessible. Use either an `'aria-label'` or `'aria-labelledby'`.
The `isResizable` prop renders a vertical resize handle that is usable with both mouse and keyboard, with the relevant aria-attributes set to be accessible using screen readers as well.

## Examples

### Full

```tsx
import '@neo4j-ndl/base/lib/neo4j-ds-styles.css';

import { Checkbox, Drawer, FilledButton, TextInput } from '@neo4j-ndl/react';
import { useState } from 'react';

const Component = () => {
  const [isExpanded, setIsExpanded] = useState(true);

  const Placeholder = () => (
    <div className="w-full n-size-full n-flex n-flex-col n-items-center n-justify-center n-rounded-md n-p-token-16">
      <div className="n-border-dashed n-border-2 n-border-light-primary-bg-strong n-size-full n-flex n-flex-col n-items-center n-justify-center n-rounded-md">
        <FilledButton
          onClick={() => setIsExpanded(true)}
          htmlAttributes={{
            'aria-expanded': isExpanded,
          }}
        >
          Press to show the Drawer
        </FilledButton>
      </div>
    </div>
  );

  return (
    <div className="n-h-[calc(40vh-32px)] n-min-h-[700px] n-flex n-relative n-overflow-hidden">
      <Drawer
        type="push"
        isExpanded={isExpanded}
        onExpandedChange={() => setIsExpanded(false)}
        isResizeable={true}
        resizeableProps={{
          maxWidth: '400px',
          minWidth: '300px',
        }}
        isCloseable={true}
        isPortaled={false}
      >
        <Drawer.Header>Drawer Header</Drawer.Header>
        <Drawer.Body>
          <TextInput
            showRequiredOrOptionalLabel={true}
            moreInformationText="some information"
            label="Label"
            isDisabled={false}
            isReadOnly={false}
            helpText="Friendly text"
            isFluid={true}
          />
          <br />
          <TextInput label="Some input" value="something" />
          <br />
          <Checkbox label="Checkbox label" />
          <br />
          Some example of something.
          <br />
          <TextInput label="Some input" isDisabled={true} value="something" />
          <br />
          <TextInput
            showRequiredOrOptionalLabel={true}
            moreInformationText="some information"
            label="Label"
            isDisabled={false}
            isReadOnly={false}
            helpText="Friendly text"
            isFluid={true}
          />
          <br />
          Some example of something.
          <br />
          <TextInput label="Some input" value="something" />
          <br />
          <Checkbox label="Checkbox label" />
          <br />
          <TextInput label="Some input" value="something" />
        </Drawer.Body>
        <Drawer.Actions>
          <FilledButton onClick={() => setIsExpanded(false)} size="medium">
            Close
          </FilledButton>
        </Drawer.Actions>
      </Drawer>
      <Placeholder />
    </div>
  );
};

export default Component;
```

### Not Closeable

```tsx
import '@neo4j-ndl/base/lib/neo4j-ds-styles.css';

import { Drawer } from '@neo4j-ndl/react';

const Component = () => {
  const Placeholder = () => (
    <div className="n-size-full n-flex n-flex-col n-items-center n-justify-center n-rounded-md n-p-token-16 w-full">
      <div className="n-border-dashed n-border-2 n-border-light-primary-bg-strong n-size-full n-flex n-flex-col n-items-center n-justify-center n-rounded-md"></div>
    </div>
  );

  return (
    <div className="n-h-[calc(40vh-32px)] n-min-h-[700px] n-flex n-relative n-overflow-hidden">
      <Drawer type="push" isExpanded={true} position="left" isCloseable={false}>
        <Drawer.Header>Drawer</Drawer.Header>
        <Drawer.Body>Lorem ipsum dolor sit amet.</Drawer.Body>
      </Drawer>
      <Placeholder />
    </div>
  );
};

export default Component;
```

### Overlay

```tsx
import '@neo4j-ndl/base/lib/neo4j-ds-styles.css';

import { Drawer, FilledButton } from '@neo4j-ndl/react';
import { useRef, useState } from 'react';

const Component = () => {
  const [isExpanded, setIsExpanded] = useState(false);
  const referenceElement = useRef<HTMLButtonElement>(null);

  return (
    <div className="n-h-[calc(40vh-32px)] n-min-h-[700px] n-flex n-relative n-overflow-hidden">
      <Drawer
        isExpanded={isExpanded}
        onExpandedChange={() => setIsExpanded(false)}
        type="overlay"
        ariaLabel="Drawer"
        position="left"
        closeOnClickOutside={true}
        closeOnEscape={true}
        isCloseable={true}
        style={{ maxWidth: '400px' }}
      >
        <Drawer.Header>Drawer</Drawer.Header>
        <Drawer.Body>
          If you use an overlay drawer, you should set{' '}
          <code>closeOnClickOutside</code> to true. This is to align the mouse
          behavior with the keyboard behavior, as focus is trapped inside the
          drawer. This is to prevent the drawer from covering interactive
          elements outside the drawer.
        </Drawer.Body>
        <Drawer.Actions>
          <FilledButton onClick={() => setIsExpanded(false)} size="medium">
            Close
          </FilledButton>
        </Drawer.Actions>
      </Drawer>
      <div className="n-size-full n-flex n-flex-col n-items-center n-justify-center n-rounded-md n-p-token-16 w-full">
        <div className="n-border-dashed n-border-2 n-border-light-primary-bg-strong n-size-full n-flex n-flex-col n-items-center n-justify-center n-rounded-md">
          <FilledButton
            onClick={() => setIsExpanded(true)}
            htmlAttributes={{
              'aria-expanded': isExpanded,
            }}
            ref={referenceElement}
          >
            Press to show the Drawer
          </FilledButton>
        </div>
      </div>
    </div>
  );
};

export default Component;
```

### Portaled

```tsx
import '@neo4j-ndl/base/lib/neo4j-ds-styles.css';

import { Drawer, DropdownButton, FilledButton, Menu } from '@neo4j-ndl/react';
import { useRef, useState } from 'react';

const Component = () => {
  const [isExpanded, setIsExpanded] = useState(false);
  const [isMenuOpen, setIsMenuOpen] = useState(false);
  const anchorRef = useRef<HTMLButtonElement | null>(null);
  const referenceElementRef = useRef<HTMLButtonElement | null>(null);

  return (
    <div className="n-h-[calc(40vh-32px)] n-min-h-[700px] n-flex n-relative n-overflow-hidden">
      <Drawer
        type="modal"
        isExpanded={isExpanded}
        onExpandedChange={() => setIsExpanded(false)}
        position="left"
        closeOnEscape={true}
        ariaLabel="Drawer"
        htmlAttributes={{
          id: 'drawer',
        }}
      >
        <Drawer.Header>Drawer</Drawer.Header>
        <Drawer.Body>
          Lorem ipsum dolor sit amet.{' '}
          <DropdownButton ref={anchorRef} onClick={() => setIsMenuOpen(true)}>
            Dropdown Button
          </DropdownButton>
          <Menu
            strategy="fixed"
            portalTarget={document.getElementById('drawer')}
            anchorRef={anchorRef}
            isOpen={isMenuOpen}
            onClose={(_event) => {
              setIsMenuOpen(false);
            }}
          >
            <Menu.Item title="Menu Item 1" />
            <Menu.Item title="Menu Item 2" />
            <Menu.Item title="Menu Item 3" />
          </Menu>
        </Drawer.Body>
        <Drawer.Actions>
          <FilledButton onClick={() => setIsExpanded(false)} size="medium">
            Close
          </FilledButton>
        </Drawer.Actions>
      </Drawer>
      <div className="n-size-full n-flex n-flex-col n-items-center n-justify-center n-rounded-md n-p-token-16 w-full">
        <div className="n-border-dashed n-border-2 n-border-light-primary-bg-strong n-size-full n-flex n-flex-col n-items-center n-justify-center n-rounded-md">
          <FilledButton
            onClick={() => setIsExpanded(true)}
            htmlAttributes={{
              'aria-expanded': isExpanded,
            }}
            ref={referenceElementRef}
          >
            Press to show the Drawer
          </FilledButton>
        </div>
      </div>
    </div>
  );
};

export default Component;
```

### Push

```tsx
import { Drawer, FilledButton } from '@neo4j-ndl/react';
import { useState } from 'react';

const Component = () => {
  const [isExpanded, setIsExpanded] = useState(true);

  const Placeholder = () => (
    <div className="n-size-full n-flex n-flex-col n-items-center n-justify-center n-rounded-md n-p-token-16 w-full">
      <div className="n-border-dashed n-border-2 n-border-light-primary-bg-strong n-size-full n-flex n-flex-col n-items-center n-justify-center n-rounded-md">
        <FilledButton
          onClick={() => setIsExpanded(true)}
          htmlAttributes={{
            'aria-expanded': isExpanded,
          }}
        >
          Press to show the Drawer
        </FilledButton>
      </div>
    </div>
  );

  return (
    <div className="n-h-[calc(40vh-32px)] n-min-h-[700px] n-flex n-relative n-overflow-hidden">
      <Drawer
        type="push"
        isExpanded={isExpanded}
        onExpandedChange={() => setIsExpanded(false)}
      >
        <Drawer.Header>Drawer</Drawer.Header>
        <Drawer.Body>Lorem ipsum dolor sit amet.</Drawer.Body>
        <Drawer.Actions>
          <FilledButton onClick={() => setIsExpanded(false)} size="medium">
            Close
          </FilledButton>
        </Drawer.Actions>
      </Drawer>
      <Placeholder />
    </div>
  );
};

export default Component;
```

### Resizable

```tsx
import '@neo4j-ndl/base/lib/neo4j-ds-styles.css';

import { Drawer, FilledButton } from '@neo4j-ndl/react';
import { useState } from 'react';

const Component = () => {
  const [isExpanded, setIsExpanded] = useState(true);

  const Placeholder = () => (
    <div className="n-size-full n-flex n-flex-col n-items-center n-justify-center n-rounded-md n-p-token-16 w-full">
      <div className="n-border-dashed n-border-2 n-border-light-primary-bg-strong n-size-full n-flex n-flex-col n-items-center n-justify-center n-rounded-md">
        <FilledButton
          onClick={() => setIsExpanded(true)}
          htmlAttributes={{
            'aria-expanded': isExpanded,
          }}
        >
          Press to show the Drawer
        </FilledButton>
      </div>
    </div>
  );

  return (
    <div className="n-h-[calc(40vh-32px)] n-min-h-[700px] n-flex n-relative n-overflow-hidden">
      <Drawer
        type="push"
        isExpanded={isExpanded}
        onExpandedChange={() => setIsExpanded(false)}
        position="left"
        isResizeable={true}
        resizeableProps={{
          maxWidth: '400px',
          minWidth: '300px',
        }}
      >
        <Drawer.Header>Drawer</Drawer.Header>
        <Drawer.Body>Lorem ipsum dolor sit amet.</Drawer.Body>
        <Drawer.Actions>
          <FilledButton onClick={() => setIsExpanded(false)} size="medium">
            Close
          </FilledButton>
        </Drawer.Actions>
      </Drawer>
      <Placeholder />
    </div>
  );
};

export default Component;
```

### Right Side

```tsx
import '@neo4j-ndl/base/lib/neo4j-ds-styles.css';

import { Drawer, FilledButton } from '@neo4j-ndl/react';
import { useState } from 'react';

const Component = () => {
  const [isExpanded, setIsExpanded] = useState(true);

  const Placeholder = () => (
    <div className="n-size-full n-flex n-flex-col n-items-center n-justify-center n-rounded-md n-p-token-16 w-full">
      <div className="n-border-dashed n-border-2 n-border-light-primary-bg-strong n-size-full n-flex n-flex-col n-items-center n-justify-center n-rounded-md">
        <FilledButton
          onClick={() => setIsExpanded(true)}
          htmlAttributes={{
            'aria-expanded': isExpanded,
          }}
        >
          Press to show the Drawer
        </FilledButton>
      </div>
    </div>
  );

  return (
    <div className="n-h-[calc(40vh-32px)] n-min-h-[700px] n-flex n-relative n-overflow-hidden">
      <Placeholder />
      <Drawer
        type="push"
        isExpanded={isExpanded}
        onExpandedChange={() => setIsExpanded(false)}
        position="right"
      >
        <Drawer.Header>Drawer</Drawer.Header>
        <Drawer.Body>Lorem ipsum dolor sit amet.</Drawer.Body>
        <Drawer.Actions>
          <FilledButton onClick={() => setIsExpanded(false)} size="medium">
            Close
          </FilledButton>
        </Drawer.Actions>
      </Drawer>
    </div>
  );
};

export default Component;
```

### Scrollable

```tsx
import '@neo4j-ndl/base/lib/neo4j-ds-styles.css';

import { Checkbox, Drawer, FilledButton, TextInput } from '@neo4j-ndl/react';
import { useState } from 'react';

const Component = () => {
  const [isExpanded, setIsExpanded] = useState(true);

  const Placeholder = () => (
    <div className="w-full n-size-full n-flex n-flex-col n-items-center n-justify-center n-rounded-md n-p-token-16">
      <div className="n-border-dashed n-border-2 n-border-light-primary-bg-strong n-size-full n-flex n-flex-col n-items-center n-justify-center n-rounded-md">
        <FilledButton
          onClick={() => setIsExpanded(true)}
          htmlAttributes={{
            'aria-expanded': isExpanded,
          }}
        >
          Press to show the Drawer
        </FilledButton>
      </div>
    </div>
  );

  return (
    <div className="n-h-[calc(40vh-32px)] n-min-h-[700px] n-flex n-relative n-overflow-hidden">
      <Drawer
        type="push"
        isExpanded={isExpanded}
        onExpandedChange={() => setIsExpanded(false)}
      >
        <Drawer.Header>Drawer</Drawer.Header>
        <Drawer.Body>
          <TextInput
            showRequiredOrOptionalLabel={true}
            moreInformationText="some information"
            label="Label"
            isDisabled={false}
            isReadOnly={false}
            helpText="Friendly text"
            isFluid={true}
          />
          <br />
          <TextInput label="Some input" value="something" />
          <br />
          <Checkbox label="Checkbox label" />
          <br />
          Some example of something.
          <br />
          <TextInput label="Some input" isDisabled={true} value="something" />
          <br />
          <TextInput
            showRequiredOrOptionalLabel={true}
            moreInformationText="some information"
            label="Label"
            isDisabled={false}
            isReadOnly={false}
            helpText="Friendly text"
            isFluid={true}
          />
          <br />
          Some example of something.
          <br />
          <TextInput label="Some input" value="something" />
          <br />
          <Checkbox label="Checkbox label" />
          <br />
          <TextInput label="Some input" value="something" />
        </Drawer.Body>
      </Drawer>
      <Placeholder />
    </div>
  );
};

export default Component;
```
