# Drawer

A drawer is a secondary content surface that slides in from one edge of a layout. Use drawers for supplemental info and simple actions related to the main content.

## Best practices

### Do

- Reserve modal drawers for important tasks that are clear and quick to complete.
- Use non-modal overlay drawers for at-a-glance information that can be easily dismissed.
- Use a dialog to confirm actions that might cause data loss.

### Don't

- Open multiple overlay drawers at the same time.
- Break established placement conventions, such as navigation on the left and notifications on the right.
- Use drawers for long blocks of text.

## Behavior and states

- Overlay drawers are elevated above main page content and are modal by default.
- Drawers can be closed by interacting with the button that opened them or an included dismiss icon.
- If a drawer gathers information, alert people if they might lose progress when they close it.
- Keep multi-step tasks in drawers to two or three steps.
- Wrap body content in DrawerBody to enable scrolling when content exceeds the drawer height.
- An overlay drawer is an intrusive surface that obscures all or part of the main page content.
- Use overlay drawers to draw more attention to the content in the drawer.
- An inline drawer is a passive surface that sits side-by-side with main page content.
- Use inline drawers when it’s helpful to view and interact with page content and drawer content at the same time.
- For short information that’s related to a specific part of the main layout, a drawer may be overwhelming.
- Try a tooltip or a popover instead.
- If you need people to confirm an action they’re trying to take, use a dialog.

## Default

Source: CoreAI.

Switches between overlay and inline drawer behavior while restoring focus to the trigger.

[Download source](/coreai-design-system/source/examples/components-drawer--default.tsx)

```tsx
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { DrawerProps } from "@coreai-ds/react-components";
import { useId } from "@coreai-ds/react-components";
import * as React from 'react';
import { useRestoreFocusTarget } from "@coreai-ds/react-components";
import { useRestoreFocusSource } from "@coreai-ds/react-components";
import { Drawer } from "@coreai-ds/react-components";
import { DrawerHeader } from "@coreai-ds/react-components";
import { DrawerHeaderTitle } from "@coreai-ds/react-components";
import { Button } from "@coreai-ds/react-components";
import { Dismiss24Regular } from "@fluentui/react-icons";
import { DrawerBody } from "@coreai-ds/react-components";
import { ToggleButton } from "@coreai-ds/react-components";
import { Label } from "@coreai-ds/react-components";
import { RadioGroup } from "@coreai-ds/react-components";
import { Radio } from "@coreai-ds/react-components";

export const Default = () => {
    type DrawerType = Required<DrawerProps>['type'];
    const labelId = useId('type-label');
    const [isOpen, setIsOpen] = React.useState(false);
    const [type, setType] = React.useState<DrawerType>('overlay');
    // all Drawers need manual focus restoration attributes
    // unless (as in the case of some inline drawers, you do not want automatic focus restoration)
    const restoreFocusTargetAttributes = useRestoreFocusTarget();
    const restoreFocusSourceAttributes = useRestoreFocusSource();
    const styles = /* css */ `
      .drawer-default-example {
        border: 2px solid #ccc;
        overflow: hidden;
        display: flex;
        height: 480px;
        background-color: #fff;
      }

      .drawer-default-example__content {
        flex: 1;
        padding: var(--spacingHorizontalL);
        display: grid;
        justify-content: flex-start;
        align-items: flex-start;
        row-gap: var(--spacingVerticalXXL);
        grid-auto-rows: max-content;
      }

      .drawer-default-example__field {
        display: grid;
        row-gap: var(--spacingVerticalS);
      }
    `;
    return (<>
        <style>{styles}</style>
        <div className="drawer-default-example">
          <Drawer {...restoreFocusSourceAttributes} type={type} separator open={isOpen} onOpenChange={(_, { open }) => setIsOpen(open)}>
            <DrawerHeader>
              <DrawerHeaderTitle action={<Button appearance="subtle" aria-label="Close" icon={<Dismiss24Regular />} onClick={() => setIsOpen(false)}/>}>
                Default Drawer
              </DrawerHeaderTitle>
            </DrawerHeader>

            <DrawerBody>
              <p>Drawer content</p>
            </DrawerBody>
          </Drawer>

          <div className="drawer-default-example__content">
            {type === 'inline' ? (<ToggleButton {...restoreFocusTargetAttributes} appearance="primary" onClick={() => setIsOpen(!isOpen)} checked={isOpen}>
                Toggle
              </ToggleButton>) : (<Button {...restoreFocusTargetAttributes} appearance="primary" onClick={() => setIsOpen(!isOpen)}>
                Open
              </Button>)}

            <div className="drawer-default-example__field">
              <Label id={labelId}>Type</Label>
              <RadioGroup value={type} onChange={(_, data) => setType(data.value as DrawerType)} aria-labelledby={labelId}>
                <Radio value="overlay" label="Overlay (Default)"/>
                <Radio value="inline" label="Inline"/>
              </RadioGroup>
            </div>
          </div>
        </div>
      </>);
};

export default Default;
```

## API

Generated CoreAI prop summaries, not replacement type declarations. Most native DOM/event and ARIA props are omitted. `?` means optional; JSDoc shows defaults, deprecations, and conditional requirements. Defaults assume the standard CoreAI provider.

### Drawer API

Drawer contains supplementary content and are used for complex creation, edit, or management experiences.

```ts
interface DrawerProps {
  as?: "aside" | "div";

  /**
   * Dimmed background of dialog.
   * The default backdrop is rendered as a `<div>` with styling.
   * This slot expects a `<div>` element which will replace the default backdrop.
   * The backdrop should have `aria-hidden="true"`.
   *
   * Accepts an `appearance` prop to control backdrop visibility:
   * - `'dimmed'`: Always shows a dimmed backdrop, regardless of nesting.
   * - `'transparent'`: Always shows a transparent backdrop.
   */
  backdrop?: WithSlotShorthandValue<{ as?: "div"; } & Omit<Omit<DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & { ref?: ((instance: HTMLDivElement | null) => void) | RefObject<HTMLDivElement> | null; }, "children"> & { children?: any; } & { appearance?: "transparent" | "dimmed" | undefined; }> | null | undefined;

  /**
   * For more information refer to the [Motion docs page](https://react.fluentui.dev/?path=/docs/motion-motion-slot--docs).
   */
  backdropMotion?: PresenceMotionSlotProps<FadeParams> | (Pick<PresenceComponentProps, "imperativeRef" | "onMotionFinish" | "onMotionStart"> & Partial<Required<Pick<DrawerBaseProps, "size">>> & { as?: JSXIntrinsicElementKeys; children?: SlotRenderFunction<PresenceMotionSlotRenderProps & Required<Pick<DrawerBaseProps, "size">> & { children: JSXElement; }>; } & Partial<FadeParams> & { as?: JSXIntrinsicElementKeys | undefined; children?: SlotRenderFunction<PresenceMotionSlotRenderProps & PresenceDuration & PresenceEasing & PresenceDelay & { outOpacity?: number | undefined; inOpacity?: number | undefined; } & { children: JSXElement; }> | undefined; }) | (Pick<PresenceComponentProps, "imperativeRef" | "onMotionFinish" | "onMotionStart"> & Partial<FadeParams> & { as?: JSXIntrinsicElementKeys | undefined; children?: SlotRenderFunction<PresenceMotionSlotRenderProps & PresenceDuration & PresenceEasing & PresenceDelay & { outOpacity?: number | undefined; inOpacity?: number | undefined; } & { children: JSXElement; }> | undefined; } & Partial<Required<Pick<DrawerBaseProps, "size">>> & { as?: JSXIntrinsicElementKeys | undefined; children?: SlotRenderFunction<PresenceMotionSlotRenderProps & Required<Pick<DrawerBaseProps, "size">> & { children: JSXElement; }> | undefined; }) | null | undefined;

  children?: any;

  className?: string;

  /**
   * @deprecated OverlayDrawer can work only as a controlled component
   * and does not support uncontrolled mode i.e. defaultOpen prop
   */
  defaultOpen?: boolean;

  /**
   * Enables standard behavior according to the [HTML dialog spec](https://developer.mozilla.org/en-US/docs/Web/API/HTMLDialogElement/showModal)
   * where the focus trap involves setting outside elements inert.
   * @default false
   */
  inertTrapFocus?: boolean;

  /**
   * Dialog variations.
   *
   * `modal`: When this type of dialog is open, the rest of the page is dimmed out and cannot be interacted with.
   * The tab sequence is kept within the dialog and moving the focus outside
   * the dialog will imply closing it. This is the default type of the component.
   *
   * `non-modal`: When a non-modal dialog is open, the rest of the page is not dimmed out
   * and users can interact with the rest of the page.
   * This also implies that the tab focus can move outside the dialog when it reaches the last focusable element.
   *
   * `alert`: is a special type of modal dialogs that interrupts the user's workflow
   * to communicate an important message or ask for a decision.
   * Unlike a typical modal dialog, the user must take an action through the options given to dismiss the dialog,
   * and it cannot be dismissed through the dimmed background.
   * @default modal
   */
  modalType?: "alert" | "modal" | "non-modal";

  /**
   * Where the portal children are mounted on DOM
   * @default a new element on document.body without any styling
   */
  mountNode?: HTMLElement | { element?: HTMLElement | null; className?: string; } | null | undefined;

  /**
   * Callback fired when the component changes value from open state.
   */
  onOpenChange?: DialogOpenChangeEventHandler;

  /**
   * Controls the open state of the Drawer
   * @default false
   */
  open?: boolean;

  /**
   * Position of the drawer.
   *
   * Note: 'bottom' does not supports size, but it supports customized height.
   * @default 'start'
   */
  position?: "start" | "end" | "bottom";

  ref?: Ref<HTMLElement> | ((((instance: HTMLDivElement | null) => void) | RefObject<HTMLDivElement>) & (((instance: HTMLElement | null) => void) | RefObject<HTMLElement>));

  /**
   * Whether the drawer has a separator line.
   * @default false
   */
  separator?: boolean;

  /**
   * Size of the drawer.
   *
   * - 'small' - Drawer is 320px wide.
   * - 'medium' - Drawer is 592px wide.
   * - 'large' - Drawer is 940px wide.
   * - 'full' - Drawer is 100vw wide.
   * @default 'small'
   */
  size?: "small" | "medium" | "large" | "full";

  style?: CSSProperties;

  /**
   * For more information refer to the [Motion docs page](https://react.fluentui.dev/?path=/docs/motion-motion-slot--docs).
   */
  surfaceMotion?: PresenceMotionSlotProps<Required<Pick<DrawerBaseProps, "size" | "position"> & Pick<ProviderContextValue_unstable, "dir">>> | SurfaceMotionSlotProps | null;

  /**
   * Type of the drawer.
   *
   * - 'overlay' - Drawer is hidden by default and can be opened by clicking on the trigger.
   * - 'inline' - Drawer is stacked with the content
   * @default overlay
   */
  type?: "inline" | "overlay";

  /**
   * Decides whether the drawer should be removed from the DOM tree when it is closed.
   * This can be useful when dealing with components that may contain state that should not
   * be reset when the drawer is closed.
   * @default true
   */
  unmountOnClose?: boolean;
}
```

### DrawerBody API

DrawerBody provides with a container for the main content of a Drawer.

```ts
interface DrawerBodyProps {
  as?: "div";

  children?: any;

  className?: string;

  ref?: Ref<HTMLDivElement>;

  style?: CSSProperties;
}
```

### DrawerFooter API

DrawerFooter provides a structured footer for the drawer component.

```ts
interface DrawerFooterProps {
  as?: "footer";

  children?: any;

  className?: string;

  ref?: Ref<HTMLElement>;

  style?: CSSProperties;
}
```

### DrawerHeader API

DrawerHeader provides a structured header for the drawer component.

```ts
interface DrawerHeaderProps {
  as?: "header";

  children?: any;

  className?: string;

  ref?: Ref<HTMLElement>;

  style?: CSSProperties;
}
```

### DrawerHeaderNavigation API

DrawerHeaderNavigation provides a header navigation area for the Drawer.

```ts
interface DrawerHeaderNavigationProps {
  as?: "nav";

  children?: any;

  className?: string;

  ref?: Ref<HTMLElement>;

  style?: CSSProperties;
}
```

### DrawerHeaderTitle API

DrawerHeader provides a structured header for the drawer component.

```ts
interface DrawerHeaderTitleProps {
  /**
   * Action slot for the close button
   */
  action?: WithSlotShorthandValue<{ as?: "div"; } & Omit<Omit<DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & { ref?: ((instance: HTMLDivElement | null) => void) | RefObject<HTMLDivElement> | null; }, "children"> & { children?: any; }> | null | undefined;

  as?: "div";

  children?: any;

  className?: string;

  /**
   * By default this is a h2, but can be any heading or div.
   * If `div` is provided do not forget to also provide proper `role="heading"` and `aria-level` attributes
   */
  heading?: ({ as: "h1"; } & Omit<Omit<DetailedHTMLProps<HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>, "ref"> & { ref?: ((instance: HTMLHeadingElement | null) => void) | RefObject<HTMLHeadingElement> | null; }, "children"> & { children?: any; }) | ({ as: "h3"; } & Omit<Omit<DetailedHTMLProps<HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>, "ref"> & { ref?: ((instance: HTMLHeadingElement | null) => void) | RefObject<HTMLHeadingElement> | null; }, "children"> & { children?: any; }) | ({ as: "h4"; } & Omit<Omit<DetailedHTMLProps<HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>, "ref"> & { ref?: ((instance: HTMLHeadingElement | null) => void) | RefObject<HTMLHeadingElement> | null | undefined; }, "children"> & { children?: any; }) | ({ as: "h5"; } & Omit<Omit<DetailedHTMLProps<HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>, "ref"> & { ref?: ((instance: HTMLHeadingElement | null) => void) | RefObject<HTMLHeadingElement> | null | undefined; }, "children"> & { children?: any; }) | ({ as: "h6"; } & Omit<Omit<DetailedHTMLProps<HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>, "ref"> & { ref?: ((instance: HTMLHeadingElement | null) => void) | RefObject<HTMLHeadingElement> | null | undefined; }, "children"> & { children?: any; }) | ({ as: "div"; } & Omit<Omit<DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & { ref?: ((instance: HTMLDivElement | null) => void) | RefObject<HTMLDivElement> | null | undefined; }, "children"> & { children?: any; }) | WithSlotShorthandValue<{ as?: "h2" | undefined; } & Omit<Omit<DetailedHTMLProps<HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>, "ref"> & { ref?: ((instance: HTMLHeadingElement | null) => void) | RefObject<HTMLHeadingElement> | null | undefined; }, "children"> & { children?: any; }> | null | undefined;

  ref?: Ref<HTMLDivElement>;

  style?: CSSProperties;
}
```

### InlineDrawer API

InlineDrawer is often used for navigation that is not dismissible. As it is on the same level as
the main surface, users can still interact with other UI elements.

```ts
interface InlineDrawerProps {
  as?: "aside" | "div";

  children?: any;

  className?: string;

  /**
   * Controls the open state of the Drawer
   * @default false
   */
  open?: boolean;

  /**
   * Position of the drawer.
   *
   * Note: 'bottom' does not supports size, but it supports customized height.
   * @default 'start'
   */
  position?: "start" | "end" | "bottom";

  ref?: Ref<HTMLElement>;

  /**
   * Whether the drawer has a separator line.
   * @default false
   */
  separator?: boolean;

  /**
   * Size of the drawer.
   *
   * - 'small' - Drawer is 320px wide.
   * - 'medium' - Drawer is 592px wide.
   * - 'large' - Drawer is 940px wide.
   * - 'full' - Drawer is 100vw wide.
   * @default 'small'
   */
  size?: "small" | "medium" | "large" | "full";

  style?: CSSProperties;

  surfaceMotion?: SurfaceMotionSlotProps | null;

  /**
   * Decides whether the drawer should be removed from the DOM tree when it is closed.
   * This can be useful when dealing with components that may contain state that should not
   * be reset when the drawer is closed.
   * @default true
   */
  unmountOnClose?: boolean;
}
```

### OverlayDrawer API

OverlayDrawer contains supplementary content and are used for complex creation, edit, or management experiences.

```ts
interface OverlayDrawerProps {
  as?: "aside" | "div";

  /**
   * Dimmed background of dialog.
   * The default backdrop is rendered as a `<div>` with styling.
   * This slot expects a `<div>` element which will replace the default backdrop.
   * The backdrop should have `aria-hidden="true"`.
   *
   * Accepts an `appearance` prop to control backdrop visibility:
   * - `'dimmed'`: Always shows a dimmed backdrop, regardless of nesting.
   * - `'transparent'`: Always shows a transparent backdrop.
   */
  backdrop?: WithSlotShorthandValue<{ as?: "div"; } & Omit<Omit<DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & { ref?: ((instance: HTMLDivElement | null) => void) | RefObject<HTMLDivElement> | null; }, "children"> & { children?: any; } & { appearance?: "transparent" | "dimmed" | undefined; }> | null | undefined;

  /**
   * For more information refer to the [Motion docs page](https://react.fluentui.dev/?path=/docs/motion-motion-slot--docs).
   */
  backdropMotion?: (Pick<PresenceComponentProps, "imperativeRef" | "onMotionFinish" | "onMotionStart"> & Partial<Required<Pick<DrawerBaseProps, "size">>> & { as?: JSXIntrinsicElementKeys; children?: SlotRenderFunction<PresenceMotionSlotRenderProps & Required<Pick<DrawerBaseProps, "size">> & { children: JSXElement; }>; } & Partial<FadeParams> & { as?: JSXIntrinsicElementKeys | undefined; children?: SlotRenderFunction<PresenceMotionSlotRenderProps & PresenceDuration & PresenceEasing & PresenceDelay & { outOpacity?: number | undefined; inOpacity?: number | undefined; } & { children: JSXElement; }> | undefined; }) | null | undefined;

  children?: any;

  className?: string;

  /**
   * @deprecated OverlayDrawer can work only as a controlled component
   * and does not support uncontrolled mode i.e. defaultOpen prop
   */
  defaultOpen?: boolean;

  /**
   * Enables standard behavior according to the [HTML dialog spec](https://developer.mozilla.org/en-US/docs/Web/API/HTMLDialogElement/showModal)
   * where the focus trap involves setting outside elements inert.
   * @default false
   */
  inertTrapFocus?: boolean;

  /**
   * Dialog variations.
   *
   * `modal`: When this type of dialog is open, the rest of the page is dimmed out and cannot be interacted with.
   * The tab sequence is kept within the dialog and moving the focus outside
   * the dialog will imply closing it. This is the default type of the component.
   *
   * `non-modal`: When a non-modal dialog is open, the rest of the page is not dimmed out
   * and users can interact with the rest of the page.
   * This also implies that the tab focus can move outside the dialog when it reaches the last focusable element.
   *
   * `alert`: is a special type of modal dialogs that interrupts the user's workflow
   * to communicate an important message or ask for a decision.
   * Unlike a typical modal dialog, the user must take an action through the options given to dismiss the dialog,
   * and it cannot be dismissed through the dimmed background.
   * @default modal
   */
  modalType?: "alert" | "modal" | "non-modal";

  /**
   * Where the portal children are mounted on DOM
   * @default a new element on document.body without any styling
   */
  mountNode?: HTMLElement | { element?: HTMLElement | null; className?: string; } | null | undefined;

  /**
   * Callback fired when the component changes value from open state.
   */
  onOpenChange?: DialogOpenChangeEventHandler;

  /**
   * Controls the open state of the Drawer
   * @default false
   */
  open?: boolean;

  /**
   * Position of the drawer.
   *
   * Note: 'bottom' does not supports size, but it supports customized height.
   * @default 'start'
   */
  position?: "start" | "end" | "bottom";

  ref?: Ref<HTMLElement>;

  /**
   * Size of the drawer.
   *
   * - 'small' - Drawer is 320px wide.
   * - 'medium' - Drawer is 592px wide.
   * - 'large' - Drawer is 940px wide.
   * - 'full' - Drawer is 100vw wide.
   * @default 'small'
   */
  size?: "small" | "medium" | "large" | "full";

  style?: CSSProperties;

  /**
   * For more information refer to the [Motion docs page](https://react.fluentui.dev/?path=/docs/motion-motion-slot--docs).
   */
  surfaceMotion?: PresenceMotionSlotProps<Required<Pick<DrawerBaseProps, "size" | "position"> & Pick<ProviderContextValue_unstable, "dir">>> | null;

  /**
   * Decides whether the drawer should be removed from the DOM tree when it is closed.
   * This can be useful when dealing with components that may contain state that should not
   * be reset when the drawer is closed.
   * @default true
   */
  unmountOnClose?: boolean;
}
```

## Implementation

CoreAI 0.12.0; Fluent 9.74.9.

[Setup and dependencies](/coreai-design-system/guides/Package.md).

Import components from `@coreai-ds/react-components`. CoreAI guidance above takes precedence over API demonstration examples.

## Always Open

Source: Fluent, adapted for CoreAI.

A drawer can be always open, in which case it will not be able to be closed by the user.
This is useful for drawers that are used for navigation, and should always be visible.

[Download source](/coreai-design-system/source/examples/components-drawer--always-open.tsx)

```tsx
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import { makeStyles } from "@coreai-ds/react-components";
import { InlineDrawer } from "@coreai-ds/react-components";
import { DrawerHeader } from "@coreai-ds/react-components";
import { DrawerHeaderTitle } from "@coreai-ds/react-components";
import { DrawerBody } from "@coreai-ds/react-components";
import * as React from 'react';

const useStyles = makeStyles({
    root: {
        border: '2px solid #ccc',
        overflow: 'hidden',
        display: 'flex',
        height: '480px',
        backgroundColor: '#fff',
    },
    content: {
        flex: '1',
        padding: '16px',
        display: 'flex',
        justifyContent: 'center',
        alignItems: 'flex-start',
    },
});

export const AlwaysOpen = (): JSXElement => {
    const styles = useStyles();
    return (<div className={styles.root}>
      <InlineDrawer separator open>
        <DrawerHeader>
          <DrawerHeaderTitle>Always open</DrawerHeaderTitle>
        </DrawerHeader>

        <DrawerBody>
          <p>Drawer content</p>
        </DrawerBody>
      </InlineDrawer>

      <div className={styles.content}>
        <p>This is the page content</p>
      </div>
    </div>);
};

export default AlwaysOpen;
```

## Custom Size

Source: Fluent, adapted for CoreAI.

The Drawer can be sized to any custom width, by overriding the `width` style property.

[Download source](/coreai-design-system/source/examples/components-drawer--custom-size.tsx)

```tsx
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import { makeStyles } from "@coreai-ds/react-components";
import { tokens } from "@coreai-ds/react-components";
import * as React from 'react';
import { useRestoreFocusTarget } from "@coreai-ds/react-components";
import { useRestoreFocusSource } from "@coreai-ds/react-components";
import { OverlayDrawer } from "@coreai-ds/react-components";
import { DrawerHeader } from "@coreai-ds/react-components";
import { DrawerHeaderTitle } from "@coreai-ds/react-components";
import { Button } from "@coreai-ds/react-components";
import { Dismiss24Regular } from "@fluentui/react-icons";
import { DrawerBody } from "@coreai-ds/react-components";
import { Field } from "@coreai-ds/react-components";
import { Input } from "@coreai-ds/react-components";

const useStyles = makeStyles({
    main: {
        display: 'grid',
        justifyContent: 'flex-start',
        gridRowGap: tokens.spacingVerticalXXL,
    },
    field: {
        display: 'grid',
        gridRowGap: tokens.spacingVerticalS,
    },
});

export const CustomSize = (): JSXElement => {
    const styles = useStyles();
    const [open, setOpen] = React.useState(false);
    const [customSize, setCustomSize] = React.useState(600);
    // all Drawers need manual focus restoration attributes
    // unless (as in the case of some inline drawers, you do not want automatic focus restoration)
    const restoreFocusTargetAttributes = useRestoreFocusTarget();
    const restoreFocusSourceAttributes = useRestoreFocusSource();
    return (<div>
      <OverlayDrawer {...restoreFocusSourceAttributes} open={open} position="end" onOpenChange={(_, state) => setOpen(state.open)} style={{ width: `${customSize}px` }}>
        <DrawerHeader>
          <DrawerHeaderTitle action={<Button appearance="subtle" aria-label="Close" icon={<Dismiss24Regular />} onClick={() => setOpen(false)}/>}>
            Drawer with {customSize}px size
          </DrawerHeaderTitle>
        </DrawerHeader>

        <DrawerBody>
          <p>Drawer content</p>
        </DrawerBody>
      </OverlayDrawer>

      <div className={styles.main}>
        <Button {...restoreFocusTargetAttributes} appearance="primary" onClick={() => setOpen(true)}>
          Open Drawer
        </Button>

        <div className={styles.field}>
          <Field label="Size">
            <Input pattern="[0-9]*" value={customSize.toString()} onChange={(_, data) => setCustomSize(data.value ? parseInt(data.value, 10) : 0)}/>
          </Field>
        </div>
      </div>
    </div>);
};

export default CustomSize;
```

## Inline

Source: Fluent, adapted for CoreAI.

InlineDrawer is often used for navigation that is not dismissible.
As it is on the same level as the main surface, users can still interact with other UI elements.
This could be useful for swapping between different items in the main surface.

[Download source](/coreai-design-system/source/examples/components-drawer--inline.tsx)

```tsx
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import { makeStyles } from "@coreai-ds/react-components";
import { tokens } from "@coreai-ds/react-components";
import * as React from 'react';
import { useRestoreFocusTarget } from "@coreai-ds/react-components";
import { mergeClasses } from "@coreai-ds/react-components";
import type { InlineDrawerProps } from "@coreai-ds/react-components";
import { useRestoreFocusSource } from "@coreai-ds/react-components";
import { InlineDrawer } from "@coreai-ds/react-components";
import { DrawerHeader } from "@coreai-ds/react-components";
import { DrawerHeaderTitle } from "@coreai-ds/react-components";
import { Button } from "@coreai-ds/react-components";
import { Dismiss24Regular } from "@fluentui/react-icons";
import { DrawerBody } from "@coreai-ds/react-components";
import { ToggleButton } from "@coreai-ds/react-components";

const useStyles = makeStyles({
    root: {
        border: '2px solid #ccc',
        overflow: 'hidden',
        display: 'flex',
        height: '480px',
        backgroundColor: '#fff',
    },
    content: {
        flex: '1',
        padding: '16px',
        overflow: 'auto',
        position: 'relative',
    },
    flexColumn: {
        flexDirection: 'column',
    },
    buttons: {
        flex: '1',
        padding: '16px',
        position: 'sticky',
        top: '-16px',
        right: '-16px',
        left: '-16px',
        display: 'flex',
        flexWrap: 'wrap',
        justifyContent: 'center',
        alignItems: 'flex-start',
        columnGap: tokens.spacingHorizontalXS,
        backgroundColor: '#fff',
        transitionDuration: tokens.durationFast,
    },
});

type DrawerInlineExampleProps = InlineDrawerProps & {
    setOpen: (open: boolean) => void;
};

const capitalize = (str: string) => str.charAt(0).toUpperCase() + str.slice(1);

const DrawerInlineExample: React.FC<DrawerInlineExampleProps> = ({ setOpen, ...props }) => {
    const restoreFocusSourceAttributes = useRestoreFocusSource();
    return (<InlineDrawer {...restoreFocusSourceAttributes} {...props}>
      <DrawerHeader>
        <DrawerHeaderTitle action={<Button appearance="subtle" aria-label="Close" icon={<Dismiss24Regular />} onClick={() => setOpen(false)}/>}>
          {capitalize(props.position!)} Inline Drawer
        </DrawerHeaderTitle>
      </DrawerHeader>

      <DrawerBody>
        <p>Drawer content</p>
      </DrawerBody>
    </InlineDrawer>);
};

export const Inline = (): JSXElement => {
    const styles = useStyles();
    const [startOpen, setStartOpen] = React.useState(false);
    const [endOpen, setEndOpen] = React.useState(false);
    const [bottomOpen, setBottomOpen] = React.useState(false);
    const restoreFocusTargetAttributes = useRestoreFocusTarget();
    return (<div className={mergeClasses(styles.root, styles.flexColumn)}>
      <div className={styles.root}>
        <DrawerInlineExample as="aside" open={startOpen} setOpen={setStartOpen} position="start"/>

        <div className={styles.content}>
          <div className={styles.buttons}>
            <ToggleButton {...restoreFocusTargetAttributes} appearance="primary" onClick={() => setStartOpen(!startOpen)} checked={startOpen}>
              Toggle start
            </ToggleButton>

            <ToggleButton {...restoreFocusTargetAttributes} appearance="primary" onClick={() => setEndOpen(!endOpen)} checked={endOpen}>
              Toggle end
            </ToggleButton>

            <ToggleButton {...restoreFocusTargetAttributes} appearance="primary" onClick={() => setBottomOpen(!bottomOpen)} checked={bottomOpen}>
              Toggle bottom
            </ToggleButton>
          </div>

          {Array.from({ length: 100 }, (_, i) => (<p key={i}>
              Lorem, ipsum dolor sit amet consectetur adipisicing elit. Tempore voluptatem similique reiciendis, ipsa
              accusamus distinctio dolorum quisquam, tenetur minima animi autem nobis. Molestias totam natus, deleniti
              nam itaque placeat quisquam!
            </p>))}
        </div>

        <DrawerInlineExample open={endOpen} setOpen={setEndOpen} position="end"/>
      </div>

      <DrawerInlineExample open={bottomOpen} setOpen={setBottomOpen} position="bottom"/>
    </div>);
};

export default Inline;
```

## Keep Rendered In The DOM

Source: Fluent, adapted for CoreAI.

[Download source](/coreai-design-system/source/examples/components-drawer--keep-rendered-in-the-dom.tsx)

```tsx
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import { makeStyles } from "@coreai-ds/react-components";
import { tokens } from "@coreai-ds/react-components";
import { useId } from "@coreai-ds/react-components";
import * as React from 'react';
import type { DrawerProps } from "@coreai-ds/react-components";
import { useRestoreFocusTarget } from "@coreai-ds/react-components";
import { useRestoreFocusSource } from "@coreai-ds/react-components";
import { Drawer } from "@coreai-ds/react-components";
import { DrawerHeader } from "@coreai-ds/react-components";
import { DrawerHeaderTitle } from "@coreai-ds/react-components";
import { Button } from "@coreai-ds/react-components";
import { Dismiss24Regular } from "@fluentui/react-icons";
import { DrawerBody } from "@coreai-ds/react-components";
import { ToggleButton } from "@coreai-ds/react-components";
import { Label } from "@coreai-ds/react-components";
import { RadioGroup } from "@coreai-ds/react-components";
import { Radio } from "@coreai-ds/react-components";

const useStyles = makeStyles({
    root: {
        border: '2px solid #ccc',
        overflow: 'hidden',
        display: 'flex',
        height: '480px',
        backgroundColor: '#fff',
    },
    content: {
        flex: '1',
        padding: '16px',
        display: 'grid',
        justifyContent: 'flex-start',
        alignItems: 'flex-start',
        gridRowGap: tokens.spacingVerticalXXL,
        gridAutoRows: 'max-content',
    },
    field: {
        display: 'grid',
        gridRowGap: tokens.spacingVerticalS,
    },
});

type DrawerType = Required<DrawerProps>['type'];

export const KeepRenderedInTheDOM = (): JSXElement => {
    const styles = useStyles();
    const labelId = useId('type-label');
    const [isOpen, setIsOpen] = React.useState(false);
    const [type, setType] = React.useState<DrawerType>('overlay');
    // all Drawers need manual focus restoration attributes
    // unless (as in the case of some inline drawers, you do not want automatic focus restoration)
    const restoreFocusTargetAttributes = useRestoreFocusTarget();
    const restoreFocusSourceAttributes = useRestoreFocusSource();
    return (<div className={styles.root}>
      <Drawer {...restoreFocusSourceAttributes} type={type} separator open={isOpen} onOpenChange={(_, { open }) => setIsOpen(open)} unmountOnClose={false}>
        <DrawerHeader>
          <DrawerHeaderTitle action={<Button appearance="subtle" aria-label="Close" icon={<Dismiss24Regular />} onClick={() => setIsOpen(false)}/>}>
            Default Drawer
          </DrawerHeaderTitle>
        </DrawerHeader>

        <DrawerBody>
          <p>
            Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et
            dolore magna aliqua. Nisl pretium fusce id velit ut tortor. Leo vel fringilla est ullamcorper. Eget est
            lorem ipsum dolor sit amet consectetur adipiscing elit. In mollis nunc sed id semper risus in hendrerit
            gravida. Ullamcorper sit amet risus nullam eget felis eget. Dolor sed viverra ipsum nunc aliquet bibendum.
            Facilisi morbi tempus iaculis urna id volutpat. Porta non pulvinar neque laoreet suspendisse. Nunc id cursus
            metus aliquam eleifend mi in. A iaculis at erat pellentesque adipiscing commodo. Proin nibh nisl condimentum
            id. In hac habitasse platea dictumst vestibulum rhoncus est. Non tellus orci ac auctor augue mauris augue
            neque. Enim nulla aliquet porttitor lacus luctus accumsan tortor. Nascetur ridiculus mus mauris vitae
            ultricies leo integer. Ullamcorper eget nulla facilisi etiam dignissim. Leo in vitae turpis massa sed
            elementum tempus egestas sed.
          </p>

          <p>
            Ut enim blandit volutpat maecenas volutpat. Venenatis urna cursus eget nunc scelerisque viverra mauris.
            Neque aliquam vestibulum morbi blandit. Porttitor eget dolor morbi non. Nisi quis eleifend quam adipiscing
            vitae. Aliquam ultrices sagittis orci a scelerisque purus semper. Interdum varius sit amet mattis vulputate
            enim nulla aliquet. Ut sem viverra aliquet eget sit amet tellus cras. Sit amet tellus cras adipiscing enim
            eu turpis egestas. Amet cursus sit amet dictum sit amet justo donec enim. Neque gravida in fermentum et
            sollicitudin ac. Arcu cursus euismod quis viverra nibh cras pulvinar mattis nunc. Ultrices eros in cursus
            turpis massa tincidunt dui. Nisl rhoncus mattis rhoncus urna neque viverra justo. Odio pellentesque diam
            volutpat commodo sed egestas. Nunc mi ipsum faucibus vitae aliquet nec ullamcorper. Ipsum nunc aliquet
            bibendum enim. Faucibus ornare suspendisse sed nisi lacus sed. Sapien nec sagittis aliquam malesuada
            bibendum arcu vitae elementum. Metus vulputate eu scelerisque felis imperdiet.
          </p>

          <p>
            Consequat interdum varius sit amet mattis vulputate enim. Amet cursus sit amet dictum sit amet justo. Eget
            aliquet nibh praesent tristique magna sit. Ut consequat semper viverra nam libero justo. Pharetra massa
            massa ultricies mi. Sem viverra aliquet eget sit amet. Pulvinar mattis nunc sed blandit libero volutpat sed.
            Pharetra diam sit amet nisl suscipit adipiscing bibendum. Consectetur adipiscing elit ut aliquam. Volutpat
            diam ut venenatis tellus in metus vulputate. Scelerisque in dictum non consectetur a erat. Venenatis lectus
            magna fringilla urna porttitor rhoncus. Vitae congue mauris rhoncus aenean vel elit. Neque laoreet
            suspendisse interdum consectetur. Ultrices gravida dictum fusce ut placerat orci. Bibendum ut tristique et
            egestas quis ipsum suspendisse. Mattis rhoncus urna neque viverra justo nec ultrices dui. Elit duis
            tristique sollicitudin nibh sit amet.
          </p>

          <p>
            At risus viverra adipiscing at. Interdum posuere lorem ipsum dolor sit amet consectetur adipiscing elit.
            Nunc vel risus commodo viverra maecenas. Sit amet est placerat in egestas erat imperdiet sed euismod. Turpis
            egestas maecenas pharetra convallis posuere. Egestas tellus rutrum tellus pellentesque eu tincidunt tortor
            aliquam. Dolor sit amet consectetur adipiscing elit. Aliquam purus sit amet luctus venenatis lectus magna
            fringilla. Scelerisque fermentum dui faucibus in ornare quam viverra. Egestas maecenas pharetra convallis
            posuere morbi leo urna. A diam sollicitudin tempor id eu nisl nunc. Lectus sit amet est placerat.
          </p>

          <p>
            Mattis ullamcorper velit sed ullamcorper morbi tincidunt ornare massa eget. At tellus at urna condimentum
            mattis pellentesque id nibh. Dui faucibus in ornare quam. Tincidunt id aliquet risus feugiat in ante metus
            dictum. Adipiscing commodo elit at imperdiet dui. Dolor sed viverra ipsum nunc. Sodales neque sodales ut
            etiam sit amet nisl. Hendrerit dolor magna eget est lorem ipsum dolor sit amet. Mattis molestie a iaculis at
            erat pellentesque adipiscing. Adipiscing elit duis tristique sollicitudin nibh sit amet commodo nulla.
            Fringilla urna porttitor rhoncus dolor purus.
          </p>

          <p>
            Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et
            dolore magna aliqua. Nisl pretium fusce id velit ut tortor. Leo vel fringilla est ullamcorper. Eget est
            lorem ipsum dolor sit amet consectetur adipiscing elit. In mollis nunc sed id semper risus in hendrerit
            gravida. Ullamcorper sit amet risus nullam eget felis eget. Dolor sed viverra ipsum nunc aliquet bibendum.
            Facilisi morbi tempus iaculis urna id volutpat. Porta non pulvinar neque laoreet suspendisse. Nunc id cursus
            metus aliquam eleifend mi in. A iaculis at erat pellentesque adipiscing commodo. Proin nibh nisl condimentum
            id. In hac habitasse platea dictumst vestibulum rhoncus est. Non tellus orci ac auctor augue mauris augue
            neque. Enim nulla aliquet porttitor lacus luctus accumsan tortor. Nascetur ridiculus mus mauris vitae
            ultricies leo integer. Ullamcorper eget nulla facilisi etiam dignissim. Leo in vitae turpis massa sed
            elementum tempus egestas sed.
          </p>

          <p>
            Ut enim blandit volutpat maecenas volutpat. Venenatis urna cursus eget nunc scelerisque viverra mauris.
            Neque aliquam vestibulum morbi blandit. Porttitor eget dolor morbi non. Nisi quis eleifend quam adipiscing
            vitae. Aliquam ultrices sagittis orci a scelerisque purus semper. Interdum varius sit amet mattis vulputate
            enim nulla aliquet. Ut sem viverra aliquet eget sit amet tellus cras. Sit amet tellus cras adipiscing enim
            eu turpis egestas. Amet cursus sit amet dictum sit amet justo donec enim. Neque gravida in fermentum et
            sollicitudin ac. Arcu cursus euismod quis viverra nibh cras pulvinar mattis nunc. Ultrices eros in cursus
            turpis massa tincidunt dui. Nisl rhoncus mattis rhoncus urna neque viverra justo. Odio pellentesque diam
            volutpat commodo sed egestas. Nunc mi ipsum faucibus vitae aliquet nec ullamcorper. Ipsum nunc aliquet
            bibendum enim. Faucibus ornare suspendisse sed nisi lacus sed. Sapien nec sagittis aliquam malesuada
            bibendum arcu vitae elementum. Metus vulputate eu scelerisque felis imperdiet.
          </p>

          <p>
            Consequat interdum varius sit amet mattis vulputate enim. Amet cursus sit amet dictum sit amet justo. Eget
            aliquet nibh praesent tristique magna sit. Ut consequat semper viverra nam libero justo. Pharetra massa
            massa ultricies mi. Sem viverra aliquet eget sit amet. Pulvinar mattis nunc sed blandit libero volutpat sed.
            Pharetra diam sit amet nisl suscipit adipiscing bibendum. Consectetur adipiscing elit ut aliquam. Volutpat
            diam ut venenatis tellus in metus vulputate. Scelerisque in dictum non consectetur a erat. Venenatis lectus
            magna fringilla urna porttitor rhoncus. Vitae congue mauris rhoncus aenean vel elit. Neque laoreet
            suspendisse interdum consectetur. Ultrices gravida dictum fusce ut placerat orci. Bibendum ut tristique et
            egestas quis ipsum suspendisse. Mattis rhoncus urna neque viverra justo nec ultrices dui. Elit duis
            tristique sollicitudin nibh sit amet.
          </p>
        </DrawerBody>
      </Drawer>

      <div className={styles.content}>
        {type === 'inline' ? (<ToggleButton {...restoreFocusTargetAttributes} appearance="primary" onClick={() => setIsOpen(!isOpen)} checked={isOpen}>
            Toggle
          </ToggleButton>) : (<Button {...restoreFocusTargetAttributes} appearance="primary" onClick={() => setIsOpen(!isOpen)}>
            Open
          </Button>)}

        <div className={styles.field}>
          <Label id={labelId}>Type</Label>
          <RadioGroup value={type} onChange={(_, data) => setType(data.value as DrawerType)} aria-labelledby={labelId}>
            <Radio value="overlay" label="Overlay (Default)"/>
            <Radio value="inline" label="Inline"/>
          </RadioGroup>
        </div>
      </div>
    </div>);
};

export default KeepRenderedInTheDOM;
```

## Motion Custom

Source: Fluent, adapted for CoreAI.

Drawer animations can be customized using the [Motion APIs](https://react.fluentui.dev/?path=/docs/motion-apis-createpresencecomponent--docs), together with the `surfaceMotion` prop.

[Download source](/coreai-design-system/source/examples/components-drawer--motion-custom.tsx)

```tsx
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import { makeStyles } from "@coreai-ds/react-components";
import { tokens } from "@coreai-ds/react-components";
import * as React from 'react';
import { InlineDrawer } from "@coreai-ds/react-components";
import { createPresenceComponent } from "@coreai-ds/react-components";
import { motionTokens } from "@coreai-ds/react-components";
import { DrawerHeader } from "@coreai-ds/react-components";
import { DrawerHeaderTitle } from "@coreai-ds/react-components";
import { Button } from "@coreai-ds/react-components";
import { Dismiss24Regular } from "@fluentui/react-icons";
import { DrawerBody } from "@coreai-ds/react-components";

const drawerWidth = '320px';

const useStyles = makeStyles({
    root: {
        border: '2px solid #ccc',
        overflow: 'hidden',
        position: 'relative',
        display: 'flex',
        height: '480px',
        backgroundColor: tokens.colorNeutralBackground1,
    },
    drawer: {
        width: drawerWidth,
        border: '1px solid',
    },
    content: {
        flex: '1',
        padding: '16px',
        display: 'grid',
        justifyContent: 'flex-start',
        alignItems: 'flex-start',
        gap: tokens.spacingVerticalM,
        gridAutoRows: 'max-content',
        boxSizing: 'border-box',
        position: 'absolute',
        inset: 0,
        backgroundColor: tokens.colorNeutralBackground1,
        border: `1px solid ${tokens.colorNeutralBackground1}`,
    },
});

const drawerMargin = tokens.spacingVerticalM;

/*
 * Create a custom DrawerMotion component that animates the drawer surface.
 */
const DrawerMotion = createPresenceComponent(() => {
    const keyframes = [
        {
            opacity: 0,
            transform: 'translate3D(-100%, 0, 0)',
            margin: 0,
            backgroundColor: tokens.colorNeutralBackground1,
            borderColor: tokens.colorNeutralBackground1,
            borderRadius: 0,
        },
        {
            opacity: 1,
            transform: 'translate3D(0, 0, 0)',
            margin: drawerMargin,
            backgroundColor: tokens.colorNeutralBackground3,
            borderColor: tokens.colorNeutralBackground4,
            borderRadius: tokens.borderRadiusXLarge,
        },
    ];
    return {
        enter: {
            keyframes,
            duration: motionTokens.durationNormal,
            easing: motionTokens.curveDecelerateMin,
        },
        exit: {
            keyframes: [...keyframes].reverse(),
            duration: motionTokens.durationSlow,
            easing: motionTokens.curveAccelerateMin,
        },
    };
});

/*
 * Create a custom ContentMotion component that animates the content element.
 */
const ContentMotion = createPresenceComponent(() => {
    const keyframes = [
        {
            transform: 'translate3D(0, 0, 0)',
            width: '100%',
            margin: 0,
            backgroundColor: tokens.colorNeutralBackground1,
            borderColor: tokens.colorNeutralBackground1,
            borderRadius: 0,
        },
        {
            transform: `translate3D(calc(${drawerWidth} + ${drawerMargin} * 2), 0, 0)`,
            width: `calc(100% - ${drawerWidth} - ${drawerMargin} * 3)`,
            margin: `${drawerMargin} 0`,
            backgroundColor: tokens.colorNeutralBackground3,
            borderColor: tokens.colorNeutralBackground4,
            borderRadius: tokens.borderRadiusXLarge,
        },
    ];
    return {
        enter: {
            keyframes,
            duration: motionTokens.durationGentle,
            easing: motionTokens.curveDecelerateMin,
        },
        exit: {
            keyframes: [...keyframes].reverse(),
            duration: motionTokens.durationGentle,
            easing: motionTokens.curveAccelerateMin,
        },
    };
});

export const MotionCustom = (): JSXElement => {
    const styles = useStyles();
    const [isOpen, setIsOpen] = React.useState(false);
    return (<div className={styles.root}>
      <InlineDrawer className={styles.drawer} 
    // Override motion settings for the drawer surface
    surfaceMotion={{ children: (_, props) => <DrawerMotion {...props}/> }} separator open={isOpen}>
        <DrawerHeader>
          <DrawerHeaderTitle action={<Button appearance="subtle" aria-label="Close" icon={<Dismiss24Regular />} onClick={() => setIsOpen(false)}/>}>
            Default Drawer
          </DrawerHeaderTitle>
        </DrawerHeader>

        <DrawerBody>
          <p>Drawer content</p>
        </DrawerBody>
      </InlineDrawer>

      <ContentMotion visible={isOpen}>
        <div className={styles.content}>
          <Button appearance="primary" onClick={() => setIsOpen(!isOpen)}>
            Toggle Drawer
          </Button>

          <p>Drawer content</p>
        </div>
      </ContentMotion>
    </div>);
};

export default MotionCustom;
```

## Motion Disabled

Source: Fluent, adapted for CoreAI.

To disable the Drawer transition animation, you can set both `surfaceMotion` and `backdropMotion` props of the Drawer to `null`.

[Download source](/coreai-design-system/source/examples/components-drawer--motion-disabled.tsx)

```tsx
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import { makeStyles } from "@coreai-ds/react-components";
import { tokens } from "@coreai-ds/react-components";
import { useId } from "@coreai-ds/react-components";
import * as React from 'react';
import type { DrawerProps } from "@coreai-ds/react-components";
import { useRestoreFocusTarget } from "@coreai-ds/react-components";
import { useRestoreFocusSource } from "@coreai-ds/react-components";
import { Drawer } from "@coreai-ds/react-components";
import { DrawerHeader } from "@coreai-ds/react-components";
import { DrawerHeaderTitle } from "@coreai-ds/react-components";
import { Button } from "@coreai-ds/react-components";
import { Dismiss24Regular } from "@fluentui/react-icons";
import { DrawerBody } from "@coreai-ds/react-components";
import { Label } from "@coreai-ds/react-components";
import { RadioGroup } from "@coreai-ds/react-components";
import { Radio } from "@coreai-ds/react-components";

const useStyles = makeStyles({
    root: {
        border: '2px solid #ccc',
        overflow: 'hidden',
        display: 'flex',
        height: '480px',
        backgroundColor: '#fff',
    },
    content: {
        flex: '1',
        padding: '16px',
        display: 'grid',
        justifyContent: 'flex-start',
        alignItems: 'flex-start',
        gap: tokens.spacingVerticalXXL,
        gridAutoRows: 'max-content',
    },
    field: {
        display: 'grid',
        gap: tokens.spacingVerticalS,
    },
});

type DrawerType = Required<DrawerProps>['type'];

export const MotionDisabled = (): JSXElement => {
    const styles = useStyles();
    const labelId = useId('type-label');
    const [isOpen, setIsOpen] = React.useState(false);
    const [type, setType] = React.useState<DrawerType>('overlay');
    // all Drawers need manual focus restoration attributes
    // unless (as in the case of some inline drawers, you do not want automatic focus restoration)
    const restoreFocusTargetAttributes = useRestoreFocusTarget();
    const restoreFocusSourceAttributes = useRestoreFocusSource();
    return (<div className={styles.root}>
      <Drawer backdropMotion={null} surfaceMotion={null} type={type} {...restoreFocusSourceAttributes} separator open={isOpen} onOpenChange={(_, { open }) => setIsOpen(open)}>
        <DrawerHeader>
          <DrawerHeaderTitle action={<Button appearance="subtle" aria-label="Close" icon={<Dismiss24Regular />} onClick={() => setIsOpen(false)}/>}>
            Default Drawer
          </DrawerHeaderTitle>
        </DrawerHeader>

        <DrawerBody>
          <p>Drawer content</p>
        </DrawerBody>
      </Drawer>

      <div className={styles.content}>
        <Button {...restoreFocusTargetAttributes} appearance="primary" onClick={() => setIsOpen(!isOpen)}>
          {type === 'inline' ? 'Toggle' : 'Open'}
        </Button>

        <div className={styles.field}>
          <Label id={labelId}>Type</Label>
          <RadioGroup value={type} onChange={(_, data) => setType(data.value as DrawerType)} aria-labelledby={labelId}>
            <Radio value="overlay" label="Overlay (Default)"/>
            <Radio value="inline" label="Inline"/>
          </RadioGroup>
        </div>
      </div>
    </div>);
};

export default MotionDisabled;
```

## Multiple Levels

Source: Fluent, adapted for CoreAI.

When there is a need to display multiple levels of content, the drawer can be used to display them.
It is not recommended to invoke one drawer from another, as it can lead to a confusing experience for the user.
Instead, when a second level of a Drawer is required, the L2 content pushes the L1 Drawer content to the side and out of the Drawer.



This can be achieved by using the Motion APIs to animate the inner content of the Drawer.

[Download source](/coreai-design-system/source/examples/components-drawer--multiple-levels.tsx)

```tsx
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import { makeStyles } from "@coreai-ds/react-components";
import * as React from 'react';
import { useRestoreFocusTarget } from "@coreai-ds/react-components";
import { useRestoreFocusSource } from "@coreai-ds/react-components";
import { OverlayDrawer } from "@coreai-ds/react-components";
import { DrawerHeader } from "@coreai-ds/react-components";
import { DrawerHeaderNavigation } from "@coreai-ds/react-components";
import { Toolbar } from "@coreai-ds/react-components";
import { ToolbarGroup } from "@coreai-ds/react-components";
import { createPresenceComponentVariant } from "@coreai-ds/react-components";
import { Scale } from "@fluentui/react-motion-components-preview";
import { motionTokens } from "@coreai-ds/react-components";
import { ToolbarButton } from "@coreai-ds/react-components";
import { ArrowLeft24Regular } from "@fluentui/react-icons";
import { Calendar24Regular } from "@fluentui/react-icons";
import { Settings24Regular } from "@fluentui/react-icons";
import { Dismiss24Regular } from "@fluentui/react-icons";
import { createPresenceComponent } from "@coreai-ds/react-components";
import { fadeAtom } from "@fluentui/react-motion-components-preview";
import { slideAtom } from "@fluentui/react-motion-components-preview";
import { DrawerBody } from "@coreai-ds/react-components";
import { DrawerHeaderTitle } from "@coreai-ds/react-components";
import { DrawerFooter } from "@coreai-ds/react-components";
import { Button } from "@coreai-ds/react-components";

const useStyles = makeStyles({
    toolbar: {
        justifyContent: 'space-between',
    },
    body: {
        flex: '1',
        width: '100%',
        maxWidth: '100%',
        position: 'relative',
    },
    level: {
        position: 'absolute',
        top: 0,
        left: 0,
        right: 0,
        bottom: 0,
        ':first-child': {
            paddingTop: 0,
        },
        ':last-child': {
            paddingBottom: 0,
        },
    },
    footer: {
        justifyContent: 'space-between',
    },
});

const IconPresenceMotion = createPresenceComponentVariant(Scale, {
    duration: motionTokens.durationNormal,
    easing: motionTokens.curveEasyEase,
});

const BodyPresenceMotion = createPresenceComponent<{
    level: 1 | 2;
}>(({ level }) => {
    const duration = motionTokens.durationNormal;
    const easing = motionTokens.curveEasyEase;
    const outX = level === 1 ? '-100%' : '100%';
    return {
        enter: [
            fadeAtom({ direction: 'enter', duration, easing }),
            slideAtom({ direction: 'enter', duration, easing, outX }),
        ],
        exit: [fadeAtom({ direction: 'exit', duration, easing }), slideAtom({ direction: 'exit', duration, easing, outX })],
    };
});

export const MultipleLevels = (): JSXElement => {
    const styles = useStyles();
    const [isOpen, setIsOpen] = React.useState(false);
    const [level, setLevel] = React.useState<1 | 2>(1);
    // all Drawers need manual focus restoration attributes
    // unless (as in the case of some inline drawers, you do not want automatic focus restoration)
    const restoreFocusTargetAttributes = useRestoreFocusTarget();
    const restoreFocusSourceAttributes = useRestoreFocusSource();
    return (<div>
      <OverlayDrawer {...restoreFocusSourceAttributes} position="start" open={isOpen} onOpenChange={(_, { open }) => setIsOpen(open)}>
        <DrawerHeader>
          <DrawerHeaderNavigation>
            <Toolbar className={styles.toolbar}>
              <ToolbarGroup>
                <IconPresenceMotion visible={level === 2} unmountOnExit>
                  <ToolbarButton aria-label="Back" appearance="subtle" icon={<ArrowLeft24Regular />} onClick={() => setLevel(1)}/>
                </IconPresenceMotion>
              </ToolbarGroup>

              <ToolbarGroup>
                <IconPresenceMotion visible={level === 1} unmountOnExit>
                  <ToolbarButton aria-label="Go to calendar" appearance="subtle" icon={<Calendar24Regular />} onClick={() => setLevel(2)}/>
                </IconPresenceMotion>
                <ToolbarButton aria-label="Settings" appearance="subtle" icon={<Settings24Regular />}/>
                <ToolbarButton aria-label="Close panel" appearance="subtle" icon={<Dismiss24Regular />} onClick={() => setIsOpen(false)}/>
              </ToolbarGroup>
            </Toolbar>
          </DrawerHeaderNavigation>
        </DrawerHeader>

        <div className={styles.body}>
          <BodyPresenceMotion level={1} visible={level === 1} unmountOnExit>
            <DrawerBody className={styles.level}>
              <DrawerHeaderTitle>Level 1 title</DrawerHeaderTitle>
              <p>Level 1 content</p>
            </DrawerBody>
          </BodyPresenceMotion>

          <BodyPresenceMotion level={2} visible={level === 2} unmountOnExit>
            <DrawerBody className={styles.level}>
              <DrawerHeaderTitle>Level 2 title</DrawerHeaderTitle>
              <p>Level 2 content</p>
            </DrawerBody>
          </BodyPresenceMotion>
        </div>

        <DrawerFooter className={styles.footer}>
          <Button appearance="subtle" disabled={level === 1} onClick={() => setLevel(1)}>
            Previous
          </Button>

          <Button appearance="primary" disabled={level === 2} onClick={() => setLevel(2)}>
            Next
          </Button>
        </DrawerFooter>
      </OverlayDrawer>

      <Button {...restoreFocusTargetAttributes} appearance="primary" onClick={() => setIsOpen(true)}>
        Open Drawer
      </Button>
    </div>);
};

export default MultipleLevels;
```

## Overlay

Source: Fluent, adapted for CoreAI.

OverlayDrawer contains supplementary content and is used for complex creation, edit, or management experiences.
For example, viewing details about an item in a list or editing settings.
By default, drawer is blocking and signifies that the user's full attention is required when making configurations.

[Download source](/coreai-design-system/source/examples/components-drawer--overlay.tsx)

```tsx
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import * as React from 'react';
import { useRestoreFocusTarget } from "@coreai-ds/react-components";
import { useRestoreFocusSource } from "@coreai-ds/react-components";
import { OverlayDrawer } from "@coreai-ds/react-components";
import { DrawerHeader } from "@coreai-ds/react-components";
import { DrawerHeaderTitle } from "@coreai-ds/react-components";
import { Button } from "@coreai-ds/react-components";
import { Dismiss24Regular } from "@fluentui/react-icons";
import { DrawerBody } from "@coreai-ds/react-components";

export const Overlay = (): JSXElement => {
    const [isOpen, setIsOpen] = React.useState(false);
    // all Drawers need manual focus restoration attributes
    // unless (as in the case of some inline drawers, you do not want automatic focus restoration)
    const restoreFocusTargetAttributes = useRestoreFocusTarget();
    const restoreFocusSourceAttributes = useRestoreFocusSource();
    return (<div>
      <OverlayDrawer as="aside" {...restoreFocusSourceAttributes} open={isOpen} onOpenChange={(_, { open }) => setIsOpen(open)}>
        <DrawerHeader>
          <DrawerHeaderTitle action={<Button appearance="subtle" aria-label="Close" icon={<Dismiss24Regular />} onClick={() => setIsOpen(false)}/>}>
            Overlay Drawer
          </DrawerHeaderTitle>
        </DrawerHeader>

        <DrawerBody>
          <p>Drawer content</p>
        </DrawerBody>
      </OverlayDrawer>

      <Button {...restoreFocusTargetAttributes} appearance="primary" onClick={() => setIsOpen(true)}>
        Open Drawer
      </Button>
    </div>);
};

export default Overlay;
```

## Overlay Inside Container

Source: Fluent, adapted for CoreAI.

The overlay Drawer can be rendered inside a specific container by setting the `mountNode` prop to the desired container element.
This approach is useful when you need the Drawer to appear within a particular section of the DOM, rather than being attached to the root element.

[Download source](/coreai-design-system/source/examples/components-drawer--overlay-inside-container.tsx)

```tsx
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import * as React from 'react';
import { makeStyles } from "@coreai-ds/react-components";
import { tokens } from "@coreai-ds/react-components";
import { useRestoreFocusTarget } from "@coreai-ds/react-components";
import { useRestoreFocusSource } from "@coreai-ds/react-components";
import { OverlayDrawer } from "@coreai-ds/react-components";
import { DrawerHeader } from "@coreai-ds/react-components";
import { DrawerHeaderTitle } from "@coreai-ds/react-components";
import { Button } from "@coreai-ds/react-components";
import { Dismiss24Regular } from "@fluentui/react-icons";
import { DrawerBody } from "@coreai-ds/react-components";

const useStyles = makeStyles({
    root: {
        display: 'flex',
        alignItems: 'flex-start',
        gap: tokens.spacingHorizontalL,
    },
    container: {
        width: '500px',
        height: '300px',
        padding: `${tokens.spacingVerticalL} ${tokens.spacingHorizontalL}`,
        position: 'relative',
        overflow: 'hidden',
        border: `${tokens.strokeWidthThicker} solid ${tokens.colorNeutralStroke1}`,
        backgroundColor: tokens.colorBrandBackground2,
    },
});

export const OverlayInsideContainer = (): JSXElement => {
    const [isOpen, setIsOpen] = React.useState(false);
    const ref = React.useRef<HTMLDivElement>(null);
    const styles = useStyles();
    // all Drawers need manual focus restoration attributes
    // unless (as in the case of some inline drawers, you do not want automatic focus restoration)
    const restoreFocusTargetAttributes = useRestoreFocusTarget();
    const restoreFocusSourceAttributes = useRestoreFocusSource();
    return (<div className={styles.root}>
      <div className={styles.container} ref={ref}>
        <OverlayDrawer as="aside" {...restoreFocusSourceAttributes} mountNode={ref.current} open={isOpen} onOpenChange={(_, { open }) => setIsOpen(open)}>
          <DrawerHeader>
            <DrawerHeaderTitle action={<Button appearance="subtle" aria-label="Close" icon={<Dismiss24Regular />} onClick={() => setIsOpen(false)}/>}>
              Overlay Drawer
            </DrawerHeaderTitle>
          </DrawerHeader>

          <DrawerBody>
            <p>Drawer content</p>
          </DrawerBody>
        </OverlayDrawer>

        <p>Drawer will be rendered within this container</p>
      </div>

      <Button {...restoreFocusTargetAttributes} appearance="primary" onClick={() => setIsOpen(true)}>
        Open Drawer
      </Button>
    </div>);
};

export default OverlayInsideContainer;
```

## Overlay No Modal

Source: Fluent, adapted for CoreAI.

An overlay is optional depending on whether or not interacting with the background content is beneficial to the user's context/scenario.
By setting the `modalType` prop to `non-modal`, the Drawer will not be blocking and the user can interact with the background content.

[Download source](/coreai-design-system/source/examples/components-drawer--overlay-no-modal.tsx)

```tsx
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import * as React from 'react';
import { useRestoreFocusTarget } from "@coreai-ds/react-components";
import { useRestoreFocusSource } from "@coreai-ds/react-components";
import { OverlayDrawer } from "@coreai-ds/react-components";
import { DrawerHeader } from "@coreai-ds/react-components";
import { DrawerHeaderTitle } from "@coreai-ds/react-components";
import { Button } from "@coreai-ds/react-components";
import { Dismiss24Regular } from "@fluentui/react-icons";
import { DrawerBody } from "@coreai-ds/react-components";

export const OverlayNoModal = (): JSXElement => {
    const [isOpen, setIsOpen] = React.useState(false);
    // all Drawers need manual focus restoration attributes
    // unless (as in the case of some inline drawers, you do not want automatic focus restoration)
    const restoreFocusTargetAttributes = useRestoreFocusTarget();
    const restoreFocusSourceAttributes = useRestoreFocusSource();
    return (<div>
      <OverlayDrawer modalType="non-modal" {...restoreFocusSourceAttributes} open={isOpen} onOpenChange={(_, { open }) => setIsOpen(open)}>
        <DrawerHeader>
          <DrawerHeaderTitle action={<Button appearance="subtle" aria-label="Close" icon={<Dismiss24Regular />} onClick={() => setIsOpen(false)}/>}>
            Overlay Drawer
          </DrawerHeaderTitle>
        </DrawerHeader>

        <DrawerBody>
          <p>Drawer content</p>
        </DrawerBody>
      </OverlayDrawer>

      <Button {...restoreFocusTargetAttributes} appearance="primary" onClick={() => setIsOpen(!isOpen)}>
        Toggle
      </Button>
    </div>);
};

export default OverlayNoModal;
```

## Position

Source: Fluent, adapted for CoreAI.

When a Drawer is invoked, it slides in from either the start or end side, or bottom of the screen.
This can be specified by the `position` prop.

[Download source](/coreai-design-system/source/examples/components-drawer--position.tsx)

```tsx
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import { makeStyles } from "@coreai-ds/react-components";
import { tokens } from "@coreai-ds/react-components";
import * as React from 'react';
import type { DrawerProps } from "@coreai-ds/react-components";
import { useRestoreFocusTarget } from "@coreai-ds/react-components";
import { useRestoreFocusSource } from "@coreai-ds/react-components";
import { OverlayDrawer } from "@coreai-ds/react-components";
import { DrawerHeader } from "@coreai-ds/react-components";
import { DrawerHeaderTitle } from "@coreai-ds/react-components";
import { Button } from "@coreai-ds/react-components";
import { Dismiss24Regular } from "@fluentui/react-icons";
import { DrawerBody } from "@coreai-ds/react-components";

const useStyles = makeStyles({
    content: {
        display: 'flex',
        justifyContent: 'center',
        alignItems: 'flex-start',
        columnGap: tokens.spacingHorizontalXS,
    },
});

const capitalize = (str: string) => str.charAt(0).toUpperCase() + str.slice(1);

export const Position = (): JSXElement => {
    const styles = useStyles();
    const [isOpen, setIsOpen] = React.useState(false);
    const [position, setPosition] = React.useState<Required<DrawerProps>['position']>('start');
    const onClickStartButton = React.useCallback(() => {
        setPosition('start');
        setIsOpen(true);
    }, []);
    const onClickEndButton = React.useCallback(() => {
        setPosition('end');
        setIsOpen(true);
    }, []);
    const onClickBottomButton = React.useCallback(() => {
        setPosition('bottom');
        setIsOpen(true);
    }, []);
    // all Drawers need manual focus restoration attributes
    // unless (as in the case of some inline drawers, you do not want automatic focus restoration)
    const restoreFocusTargetAttributes = useRestoreFocusTarget();
    const restoreFocusSourceAttributes = useRestoreFocusSource();
    return (<div>
      <OverlayDrawer position={position} {...restoreFocusSourceAttributes} open={isOpen} onOpenChange={(_, { open }) => setIsOpen(open)}>
        <DrawerHeader>
          <DrawerHeaderTitle action={<Button appearance="subtle" aria-label="Close" icon={<Dismiss24Regular />} onClick={() => setIsOpen(false)}/>}>
            {capitalize(position)} Drawer
          </DrawerHeaderTitle>
        </DrawerHeader>

        <DrawerBody>
          <p>Drawer content</p>
        </DrawerBody>
      </OverlayDrawer>

      <div className={styles.content}>
        <Button {...restoreFocusTargetAttributes} appearance="primary" onClick={onClickStartButton}>
          Open start
        </Button>

        <Button {...restoreFocusTargetAttributes} appearance="primary" onClick={onClickEndButton}>
          Open end
        </Button>

        <Button {...restoreFocusTargetAttributes} appearance="primary" onClick={onClickBottomButton}>
          Open Bottom
        </Button>
      </div>
    </div>);
};

export default Position;
```

## Prevent Close

Source: Fluent, adapted for CoreAI.

By setting the `modalType` prop to `alert` and not providing an onOpenChange handler, the Drawer will not be closable by clicking outside nor using the "ESC" key.
This is useful for scenarios where the user must interact with the Drawer before continuing, when opening a Drawer is a critical action or when multiple Drawers are open at the same time.

[Download source](/coreai-design-system/source/examples/components-drawer--prevent-close.tsx)

```tsx
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import * as React from 'react';
import { useRestoreFocusTarget } from "@coreai-ds/react-components";
import { useRestoreFocusSource } from "@coreai-ds/react-components";
import { OverlayDrawer } from "@coreai-ds/react-components";
import { DrawerHeader } from "@coreai-ds/react-components";
import { DrawerHeaderTitle } from "@coreai-ds/react-components";
import { Button } from "@coreai-ds/react-components";
import { Dismiss24Regular } from "@fluentui/react-icons";
import { DrawerBody } from "@coreai-ds/react-components";

export const PreventClose = (): JSXElement => {
    const [open, setOpen] = React.useState(false);
    // all Drawers need manual focus restoration attributes
    // unless (as in the case of some inline drawers, you do not want automatic focus restoration)
    const restoreFocusTargetAttributes = useRestoreFocusTarget();
    const restoreFocusSourceAttributes = useRestoreFocusSource();
    return (<div>
      <OverlayDrawer {...restoreFocusSourceAttributes} position="end" open={open} modalType="alert">
        <DrawerHeader>
          <DrawerHeaderTitle action={<Button appearance="subtle" aria-label="Close" icon={<Dismiss24Regular />} onClick={() => setOpen(false)}/>}>
            Prevent close with Esc or outside click
          </DrawerHeaderTitle>
        </DrawerHeader>

        <DrawerBody>
          <p>This drawer cannot be closed when clicking outside nor using the "ESC" key</p>
        </DrawerBody>
      </OverlayDrawer>

      <Button {...restoreFocusTargetAttributes} appearance="primary" onClick={() => setOpen(true)}>
        Open Drawer
      </Button>
    </div>);
};

export default PreventClose;
```

## Resizable

Source: Fluent, adapted for CoreAI.

This example shows how to implement a resizable drawer.

[Download source](/coreai-design-system/source/examples/components-drawer--resizable.tsx)

```tsx
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import { makeStyles } from "@coreai-ds/react-components";
import { tokens } from "@coreai-ds/react-components";
import { shorthands } from "@coreai-ds/react-components";
import * as React from 'react';
import { useId } from "@coreai-ds/react-components";
import type { InputProps } from "@coreai-ds/react-components";
import { mergeClasses } from "@coreai-ds/react-components";
import { InlineDrawer } from "@coreai-ds/react-components";
import { DrawerHeader } from "@coreai-ds/react-components";
import { DrawerHeaderTitle } from "@coreai-ds/react-components";
import { DrawerBody } from "@coreai-ds/react-components";
import { Dialog } from "@coreai-ds/react-components";
import { DialogTrigger } from "@coreai-ds/react-components";
import { Button } from "@coreai-ds/react-components";
import { DialogSurface } from "@coreai-ds/react-components";
import { DialogBody } from "@coreai-ds/react-components";
import { DialogTitle } from "@coreai-ds/react-components";
import { Dismiss20Regular } from "@fluentui/react-icons";
import { DialogContent } from "@coreai-ds/react-components";
import { Label } from "@coreai-ds/react-components";
import { Input } from "@coreai-ds/react-components";
import { DialogActions } from "@coreai-ds/react-components";

const useStyles = makeStyles({
    root: {
        border: '2px solid #ccc',
        overflow: 'hidden',
        display: 'flex',
        height: '480px',
        backgroundColor: '#fff',
        userSelect: 'auto',
    },
    rootResizerActive: {
        userSelect: 'none',
    },
    container: {
        position: 'relative',
    },
    drawer: {
        willChange: 'width',
        transitionProperty: 'width',
        transitionDuration: '16.666ms', // 60fps
    },
    resizer: {
        width: '24px',
        height: '100%',
        position: 'absolute',
        top: 0,
        right: 0,
        bottom: 0,
        cursor: 'col-resize',
        border: 'none',
        minWidth: 'unset',
        borderRadius: tokens.borderRadiusNone,
        '&:before': {
            content: '""',
            position: 'absolute',
            borderRight: `1px solid ${tokens.colorNeutralBackground5}`,
            width: '1px',
            height: '100%',
            transform: 'translateX(-50%)',
            left: '50%',
        },
        ':hover': {
            borderRightWidth: '4px',
            cursor: 'col-resize',
            backgroundColor: 'transparent',
        },
        ':hover:active': {
            backgroundColor: 'transparent',
            cursor: 'col-resize',
        },
    },
    resizerActive: {
        borderRightWidth: '4px',
        borderRightColor: tokens.colorNeutralBackground5Pressed,
    },
    content: {
        margin: `${tokens.spacingVerticalXL} ${tokens.spacingHorizontalXL}`,
        flex: '1',
    },
    dialogContent: {
        display: 'flex',
        flexDirection: 'column',
    },
    errorMessage: {
        color: tokens.colorPaletteRedForeground1,
    },
    invalidInput: {
        ...shorthands.borderColor(tokens.colorPaletteRedBorder2),
    },
});

const MIN_SIDEBAR_WIDTH = 240;

export const Resizable = (): JSXElement => {
    const styles = useStyles();
    const inputRef = React.useRef<HTMLInputElement>(null);
    const [isDialogOpen, setDialogOpen] = React.useState(false);
    const animationFrame = React.useRef<number>(0);
    const sidebarRef = React.useRef<HTMLDivElement>(null);
    const [isResizing, setIsResizing] = React.useState(false);
    const [sidebarWidth, setSidebarWidth] = React.useState(320);
    const [showMessage, setShowMessage] = React.useState(false);
    const [resizeInput, setResizeInput] = React.useState<string>(sidebarWidth.toString());
    const inputId = useId('input');
    const startResizing = React.useCallback(() => setIsResizing(true), []);
    const stopResizing = React.useCallback(() => setIsResizing(false), []);
    const resize = React.useCallback(({ clientX }: {
        clientX: number;
    }) => {
        animationFrame.current = requestAnimationFrame(() => {
            if (isResizing && sidebarRef.current) {
                const newSidebarWidth = clientX - sidebarRef.current.getBoundingClientRect().left;
                setSidebarWidth(newSidebarWidth);
                setResizeInput(Math.round(newSidebarWidth).toString());
            }
        });
    }, [isResizing]);
    React.useEffect(() => {
        window.addEventListener('mousemove', resize);
        window.addEventListener('mouseup', stopResizing);
        return () => {
            cancelAnimationFrame(animationFrame.current);
            window.removeEventListener('mousemove', resize);
            window.removeEventListener('mouseup', stopResizing);
        };
    }, [resize, stopResizing]);
    React.useEffect(() => {
        if (isDialogOpen && inputRef.current) {
            inputRef.current.focus();
        }
    }, [isDialogOpen]);
    const onResizeInputChange: InputProps['onChange'] = (ev, data) => {
        if (data.value) {
            setResizeInput(data.value);
        }
    };
    const handleKeyDown = (ev: React.KeyboardEvent) => {
        if (ev.key === 'Enter') {
            submitWidth(ev);
        }
        if (ev.key === 'Escape') {
            setDialogOpen(false);
        }
    };
    function submitWidth(e: React.MouseEvent<HTMLButtonElement> | React.KeyboardEvent) {
        if (resizeInput && parseInt(resizeInput, 10) >= MIN_SIDEBAR_WIDTH) {
            setSidebarWidth(Number(resizeInput));
            setShowMessage(false);
            setDialogOpen(false);
        }
        else {
            setShowMessage(true);
            e.preventDefault();
        }
    }
    function resizeWithArrows(e: React.KeyboardEvent) {
        if (e.key === 'ArrowUp' || e.key === 'ArrowRight') {
            setSidebarWidth(prev => prev + 10);
            setResizeInput((prev: string) => (parseInt(prev, 10) + 10).toString());
        }
        else if (e.key === 'ArrowDown' || e.key === 'ArrowLeft') {
            setSidebarWidth(prev => prev - 10);
            setResizeInput((prev: string) => (parseInt(prev, 10) - 10).toString());
        }
    }
    return (<>
      <div className={mergeClasses(styles.root, isResizing && styles.rootResizerActive)}>
        <div className={styles.container}>
          <InlineDrawer open ref={sidebarRef} className={styles.drawer} style={{ width: `${sidebarWidth}px` }} onMouseDown={e => e.preventDefault()}>
            <DrawerHeader>
              <DrawerHeaderTitle>Default Drawer</DrawerHeaderTitle>
            </DrawerHeader>
            <DrawerBody>
              <p>Resizable content</p>
            </DrawerBody>
          </InlineDrawer>
          <Dialog open={isDialogOpen} onOpenChange={(event, data) => setDialogOpen(data.open)}>
            <DialogTrigger disableButtonEnhancement>
              <Button className={mergeClasses(styles.resizer, isResizing && styles.resizerActive)} onMouseDown={startResizing} aria-label="Resize drawer" role="separator" aria-orientation="vertical" onKeyDown={resizeWithArrows} aria-valuenow={sidebarWidth * 0.01} aria-valuemin={MIN_SIDEBAR_WIDTH * 0.01} aria-valuemax={100}/>
            </DialogTrigger>
            <DialogSurface>
              <DialogBody>
                <DialogTitle action={<DialogTrigger action="close">
                      <Button appearance="subtle" aria-label="close" icon={<Dismiss20Regular />}/>
                    </DialogTrigger>}>
                  Resize drawer
                </DialogTitle>
                <DialogContent>
                  <div className={styles.dialogContent}>
                    <Label htmlFor={inputId}>Enter desired drawer width pixels:</Label>
                    <Input id={inputId} ref={inputRef} onChange={onResizeInputChange} value={resizeInput} type="number" className={showMessage ? styles.invalidInput : ''} onKeyDown={handleKeyDown}/>
                    {showMessage ? (<Label className={styles.errorMessage}>
                        Recommended minimum width of the drawer should be greater than or equal to `240px`.
                      </Label>) : null}
                  </div>
                </DialogContent>
                <DialogActions>
                  <DialogTrigger disableButtonEnhancement>
                    <Button appearance="primary" onClick={e => submitWidth(e)}>
                      Resize
                    </Button>
                  </DialogTrigger>
                  <DialogTrigger disableButtonEnhancement>
                    <Button>Cancel</Button>
                  </DialogTrigger>
                </DialogActions>
              </DialogBody>
            </DialogSurface>
          </Dialog>
        </div>
        <p className={styles.content}>Resize the drawer to see the change</p>
      </div>
    </>);
};

export default Resizable;
```

## Responsive

Source: Fluent, adapted for CoreAI.

When using the `Drawer` component, the `type` prop can be used to change the drawer type based on the viewport size.
The example below will change the drawer type to `overlay` when the viewport is smaller than 720px.

[Download source](/coreai-design-system/source/examples/components-drawer--responsive.tsx)

```tsx
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import { makeStyles } from "@coreai-ds/react-components";
import { tokens } from "@coreai-ds/react-components";
import * as React from 'react';
import type { DrawerProps } from "@coreai-ds/react-components";
import { useRestoreFocusTarget } from "@coreai-ds/react-components";
import { useRestoreFocusSource } from "@coreai-ds/react-components";
import { Drawer } from "@coreai-ds/react-components";
import { DrawerHeader } from "@coreai-ds/react-components";
import { DrawerHeaderTitle } from "@coreai-ds/react-components";
import { Button } from "@coreai-ds/react-components";
import { Dismiss24Regular } from "@fluentui/react-icons";
import { DrawerBody } from "@coreai-ds/react-components";

const useStyles = makeStyles({
    root: {
        border: '2px solid #ccc',
        overflow: 'hidden',
        display: 'flex',
        height: '480px',
        backgroundColor: '#fff',
    },
    content: {
        margin: `${tokens.spacingVerticalXL} ${tokens.spacingHorizontalXL}`,
        flex: '1',
        gridRowGap: tokens.spacingVerticalXXL,
    },
});

type DrawerType = Required<DrawerProps>['type'];

export const Responsive = (): JSXElement => {
    const styles = useStyles();
    const [isOpen, setIsOpen] = React.useState(true);
    const [type, setType] = React.useState<DrawerType>('inline');
    const onMediaQueryChange = React.useCallback(({ matches }: {
        matches: boolean;
    }) => setType(matches ? 'overlay' : 'inline'), [setType]);
    React.useEffect(() => {
        const match = window.matchMedia('(max-width: 720px)');
        if (match.matches) {
            setType('overlay');
        }
        match.addEventListener('change', onMediaQueryChange);
        return () => match.removeEventListener('change', onMediaQueryChange);
    }, [onMediaQueryChange]);
    // all Drawers need manual focus restoration attributes
    // unless (as in the case of some inline drawers, you do not want automatic focus restoration)
    const restoreFocusTargetAttributes = useRestoreFocusTarget();
    const restoreFocusSourceAttributes = useRestoreFocusSource();
    return (<div className={styles.root}>
      <Drawer type={type} {...restoreFocusSourceAttributes} separator position="start" open={isOpen} onOpenChange={(_, { open }) => setIsOpen(open)}>
        <DrawerHeader>
          <DrawerHeaderTitle action={<Button appearance="subtle" aria-label="Close" icon={<Dismiss24Regular />} onClick={() => setIsOpen(false)}/>}>
            Responsive Drawer
          </DrawerHeaderTitle>
        </DrawerHeader>

        <DrawerBody>
          <p>Drawer content</p>
        </DrawerBody>
      </Drawer>

      <div className={styles.content}>
        <Button {...restoreFocusTargetAttributes} appearance="primary" onClick={() => setIsOpen(!isOpen)}>
          Toggle
        </Button>

        <p>Resize the window to see the change</p>
      </div>
    </div>);
};

export default Responsive;
```

## Separator

Source: Fluent, adapted for CoreAI.

The `separator` prop adds a line separator between the drawer and the content.
Its placement will be determined by the `position` prop

[Download source](/coreai-design-system/source/examples/components-drawer--separator.tsx)

```tsx
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import { makeStyles } from "@coreai-ds/react-components";
import { tokens } from "@coreai-ds/react-components";
import * as React from 'react';
import { mergeClasses } from "@coreai-ds/react-components";
import type { DrawerProps } from "@coreai-ds/react-components";
import { InlineDrawer } from "@coreai-ds/react-components";
import { DrawerHeader } from "@coreai-ds/react-components";
import { DrawerHeaderTitle } from "@coreai-ds/react-components";
import { Button } from "@coreai-ds/react-components";
import { Dismiss24Regular } from "@fluentui/react-icons";
import { DrawerBody } from "@coreai-ds/react-components";

const useStyles = makeStyles({
    root: {
        border: '2px solid #ccc',
        overflow: 'hidden',
        display: 'flex',
        height: '480px',
        backgroundColor: '#fff',
    },
    content: {
        flex: '1',
        padding: '16px',
        display: 'flex',
        justifyContent: 'center',
        alignItems: 'flex-start',
        columnGap: tokens.spacingHorizontalXS,
    },
    flexColumn: {
        flexDirection: 'column',
    },
});

type DrawerSeparatorExampleProps = {
    open: boolean;
    setOpen: (open: boolean) => void;
    position: DrawerProps['position'];
    className?: string;
};

const DrawerSeparatorExample: React.FC<DrawerSeparatorExampleProps> = ({ open, setOpen, position }) => {
    return (<InlineDrawer separator position={position} open={open}>
      <DrawerHeader>
        <DrawerHeaderTitle action={<Button appearance="subtle" aria-label="Close" icon={<Dismiss24Regular />} onClick={() => setOpen(false)}/>}>
          Drawer with separator
        </DrawerHeaderTitle>
      </DrawerHeader>

      <DrawerBody>
        <p>Drawer content</p>
      </DrawerBody>
    </InlineDrawer>);
};

export const Separator = (): JSXElement => {
    const styles = useStyles();
    const [startOpen, setStartOpen] = React.useState(true);
    const [endOpen, setEndOpen] = React.useState(true);
    const [bottomOpen, setBottomOpen] = React.useState(true);
    return (<div className={mergeClasses(styles.root, styles.flexColumn)}>
      <div className={styles.root} style={{ borderBottomWidth: 0 }}>
        <DrawerSeparatorExample open={startOpen} setOpen={setStartOpen} position="start"/>

        <div className={styles.content}>
          <Button appearance="primary" onClick={() => setStartOpen(!startOpen)}>
            Toggle start
          </Button>

          <Button appearance="primary" onClick={() => setEndOpen(!endOpen)}>
            Toggle end
          </Button>

          <Button appearance="primary" onClick={() => setBottomOpen(!bottomOpen)}>
            Toggle bottom
          </Button>
        </div>
        <DrawerSeparatorExample open={endOpen} setOpen={setEndOpen} position="end"/>
      </div>
      <DrawerSeparatorExample open={bottomOpen} setOpen={setBottomOpen} position="bottom"/>
    </div>);
};

export default Separator;
```

## Size

Source: Fluent, adapted for CoreAI.

The `size` prop controls the width of the drawer. The default is `small`.

[Download source](/coreai-design-system/source/examples/components-drawer--size.tsx)

```tsx
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import { makeStyles } from "@coreai-ds/react-components";
import { tokens } from "@coreai-ds/react-components";
import { useId } from "@coreai-ds/react-components";
import * as React from 'react';
import type { DrawerProps } from "@coreai-ds/react-components";
import { useRestoreFocusTarget } from "@coreai-ds/react-components";
import { useRestoreFocusSource } from "@coreai-ds/react-components";
import { OverlayDrawer } from "@coreai-ds/react-components";
import { DrawerHeader } from "@coreai-ds/react-components";
import { DrawerHeaderTitle } from "@coreai-ds/react-components";
import { Button } from "@coreai-ds/react-components";
import { Dismiss24Regular } from "@fluentui/react-icons";
import { DrawerBody } from "@coreai-ds/react-components";
import { Label } from "@coreai-ds/react-components";
import { RadioGroup } from "@coreai-ds/react-components";
import { Radio } from "@coreai-ds/react-components";

const useStyles = makeStyles({
    main: {
        display: 'grid',
        justifyContent: 'flex-start',
        gridRowGap: tokens.spacingVerticalXXL,
    },
    field: {
        display: 'grid',
        gridRowGap: tokens.spacingVerticalS,
    },
});

type DrawerSizeStory = Required<DrawerProps>['size'];

export const Size = (): JSXElement => {
    const styles = useStyles();
    const labelId = useId('size-label');
    const [open, setOpen] = React.useState(false);
    const [size, setSize] = React.useState<DrawerSizeStory>('small');
    const labelMap: Record<DrawerSizeStory, string> = {
        small: 'Small (Default)',
        medium: 'Medium',
        large: 'Large',
        full: 'Full',
    };
    // all Drawers need manual focus restoration attributes
    // unless (as in the case of some inline drawers, you do not want automatic focus restoration)
    const restoreFocusTargetAttributes = useRestoreFocusTarget();
    const restoreFocusSourceAttributes = useRestoreFocusSource();
    return (<div>
      <OverlayDrawer size={size} {...restoreFocusSourceAttributes} position="end" open={open} onOpenChange={(_, state) => setOpen(state.open)}>
        <DrawerHeader>
          <DrawerHeaderTitle action={<Button appearance="subtle" aria-label="Close" icon={<Dismiss24Regular />} onClick={() => setOpen(false)}/>}>
            {labelMap[size]} size
          </DrawerHeaderTitle>
        </DrawerHeader>

        <DrawerBody>
          <p>Drawer content</p>
        </DrawerBody>
      </OverlayDrawer>

      <div className={styles.main}>
        <Button {...restoreFocusTargetAttributes} appearance="primary" onClick={() => setOpen(true)}>
          Open Drawer
        </Button>

        <div className={styles.field}>
          <Label id={labelId}>Size</Label>
          <RadioGroup value={size} onChange={(_, data) => setSize(data.value as DrawerSizeStory)} aria-labelledby={labelId}>
            {Object.keys(labelMap).map(key => (<Radio key={key} value={key} label={labelMap[key as DrawerSizeStory]}/>))}
          </RadioGroup>
        </div>
      </div>
    </div>);
};

export default Size;
```

## With Navigation

Source: Fluent, adapted for CoreAI.

Drawers can have any type of content and one great case is to have a toolbar in the header.
Drawer ships with a `DrawerHeaderNavigation` component that can be used to display a toolbar in the header of the drawer.
This can be combined with `DrawerHeaderTitle` to display a title in the header.

[Download source](/coreai-design-system/source/examples/components-drawer--with-navigation.tsx)

```tsx
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import { makeStyles } from "@coreai-ds/react-components";
import * as React from 'react';
import { useRestoreFocusTarget } from "@coreai-ds/react-components";
import { useRestoreFocusSource } from "@coreai-ds/react-components";
import { OverlayDrawer } from "@coreai-ds/react-components";
import { DrawerHeader } from "@coreai-ds/react-components";
import { DrawerHeaderNavigation } from "@coreai-ds/react-components";
import { Button } from "@coreai-ds/react-components";
import { ArrowLeft24Regular } from "@fluentui/react-icons";
import { Toolbar } from "@coreai-ds/react-components";
import { ToolbarGroup } from "@coreai-ds/react-components";
import { ToolbarButton } from "@coreai-ds/react-components";
import { ArrowClockwise24Regular } from "@fluentui/react-icons";
import { Settings24Regular } from "@fluentui/react-icons";
import { Dismiss24Regular } from "@fluentui/react-icons";
import { DrawerHeaderTitle } from "@coreai-ds/react-components";
import { DrawerBody } from "@coreai-ds/react-components";

const useStyles = makeStyles({
    header: {
        display: 'flex',
        justifyContent: 'space-between',
    },
});

export const WithNavigation = (): JSXElement => {
    const styles = useStyles();
    const [isOpen, setIsOpen] = React.useState(false);
    // all Drawers need manual focus restoration attributes
    // unless (as in the case of some inline drawers, you do not want automatic focus restoration)
    const restoreFocusTargetAttributes = useRestoreFocusTarget();
    const restoreFocusSourceAttributes = useRestoreFocusSource();
    return (<div>
      <OverlayDrawer position="start" {...restoreFocusSourceAttributes} open={isOpen} onOpenChange={(_, { open }) => setIsOpen(open)}>
        <DrawerHeader>
          <DrawerHeaderNavigation className={styles.header}>
            <Button aria-label="Back" appearance="subtle" icon={<ArrowLeft24Regular />}/>
            <Toolbar>
              <ToolbarGroup>
                <ToolbarButton aria-label="Reload content" appearance="subtle" icon={<ArrowClockwise24Regular />}/>
                <ToolbarButton aria-label="Settings" appearance="subtle" icon={<Settings24Regular />}/>
                <ToolbarButton aria-label="Close panel" appearance="subtle" icon={<Dismiss24Regular />} onClick={() => setIsOpen(false)}/>
              </ToolbarGroup>
            </Toolbar>
          </DrawerHeaderNavigation>

          <DrawerHeaderTitle>Title goes here</DrawerHeaderTitle>
        </DrawerHeader>

        <DrawerBody>
          <p>Drawer content</p>
        </DrawerBody>
      </OverlayDrawer>

      <Button {...restoreFocusTargetAttributes} appearance="primary" onClick={() => setIsOpen(true)}>
        Open Drawer
      </Button>
    </div>);
};

export default WithNavigation;
```

## With Scroll

Source: Fluent, adapted for CoreAI.

By default, the drawer will not scroll its content when it overflows.
To enable this behavior, the DrawerBody component can be used to wrap the content of the drawer. 

Important note: if the drawer content does not contain any focusable elements, the DrawerBody itself needs
a tabIndex of 0 to ensure keyboard scroll access.

[Download source](/coreai-design-system/source/examples/components-drawer--with-scroll.tsx)

```tsx
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import { makeStyles } from "@coreai-ds/react-components";
import { tokens } from "@coreai-ds/react-components";
import { InlineDrawer } from "@coreai-ds/react-components";
import { DrawerBody } from "@coreai-ds/react-components";
import { DrawerHeader } from "@coreai-ds/react-components";
import { DrawerHeaderTitle } from "@coreai-ds/react-components";
import { DrawerFooter } from "@coreai-ds/react-components";
import { Button } from "@coreai-ds/react-components";
import * as React from 'react';

const useStyles = makeStyles({
    root: {
        display: 'flex',
        flexWrap: 'wrap',
        rowGap: tokens.spacingHorizontalXXL,
        columnGap: tokens.spacingHorizontalXXL,
    },
    drawer: {
        height: '400px',
        minWidth: '320px',
    },
});

const Body = () => {
    return (<DrawerBody tabIndex={0} role="group" aria-label="Example scrolling content">
      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Doloribus nam aut amet similique, iure vel voluptates
      cum cumque repellendus perferendis maiores officia unde in? Autem neque sequi maiores eum omnis. Lorem ipsum,
      dolor sit amet consectetur adipisicing elit. Perspiciatis ipsam explicabo tempora ipsum saepe nam. Eum aliquid
      aperiam, laborum labore excepturi nisi odio deserunt facilis error. Mollitia dolor quidem a. Lorem ipsum, dolor
      sit amet consectetur adipisicing elit. Eius soluta ea repellendus voluptatum provident ad aut unde accusantium
      sed. Officia qui praesentium repudiandae maxime molestias, non mollitia animi laboriosam quis. Lorem, ipsum dolor
      sit amet consectetur adipisicing elit. Inventore, architecto eligendi earum dolor voluptas hic minima nihil porro
      odio suscipit quaerat accusantium, aperiam, neque beatae ipsa explicabo consequatur cum quam?
    </DrawerBody>);
};

const Header = () => {
    return (<DrawerHeader>
      <DrawerHeaderTitle>Title goes here</DrawerHeaderTitle>
    </DrawerHeader>);
};

const Footer = () => {
    return (<DrawerFooter>
      <Button appearance="primary">Primary</Button>
      <Button>Secondary</Button>
    </DrawerFooter>);
};

export const WithScroll = (): JSXElement => {
    const styles = useStyles();
    return (<div className={styles.root}>
      <InlineDrawer className={styles.drawer} open>
        <Body />
      </InlineDrawer>

      <InlineDrawer className={styles.drawer} open>
        <Header />
        <Body />
      </InlineDrawer>

      <InlineDrawer className={styles.drawer} open>
        <Body />
        <Footer />
      </InlineDrawer>

      <InlineDrawer className={styles.drawer} open>
        <Header />
        <Body />
        <Footer />
      </InlineDrawer>
    </div>);
};

export default WithScroll;
```

## With Title

Source: Fluent, adapted for CoreAI.

`DrawerHeaderTitle` is a component that provides a structured heading for a Drawer and can be used to display a title and an action.
Although it works as a standalone component, it is intended to be used within a `DrawerHeader`.
The title renders an `h2` element by default but it can be customized using the `heading` prop.

[Download source](/coreai-design-system/source/examples/components-drawer--with-title.tsx)

```tsx
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import { InlineDrawer } from "@coreai-ds/react-components";
import { makeStyles } from "@coreai-ds/react-components";
import { DrawerHeader } from "@coreai-ds/react-components";
import { DrawerHeaderTitle } from "@coreai-ds/react-components";
import { Button } from "@coreai-ds/react-components";
import { Dismiss24Regular } from "@fluentui/react-icons";
import * as React from 'react';

const useStyles = makeStyles({
    drawer: {
        width: '400px',
        height: '600px',
    },
});

export const WithTitle = (): JSXElement => {
    return (<InlineDrawer className={useStyles().drawer} open>
      <DrawerHeader>
        <DrawerHeaderTitle>Drawer with title</DrawerHeaderTitle>
        <DrawerHeaderTitle heading={{ as: 'h1' }}>Drawer with custom tag</DrawerHeaderTitle>
        <DrawerHeaderTitle action={<Button appearance="subtle" aria-label="Close" icon={<Dismiss24Regular />}/>}>
          Drawer with title and action
        </DrawerHeaderTitle>
      </DrawerHeader>
    </InlineDrawer>);
};

export default WithTitle;
```

## Resources

- [Figma component](https://www.figma.com/design/eXfSQrRg3poHRgmr0ivN5V/CoreAI-Figma-Library?node-id=145579-770)
- [Fluent guidance](https://fluent2.microsoft.design/components/web/react/core/drawer/usage)