Drawer

A draggable, dismissible panel that slides in from any edge of the screen.

Default

tsx

import { Button, CloseButton, Drawer } from "@hummingbirdui/react";

export default function DrawerDefault() {
  return (
    <Drawer>
      <Drawer.Trigger asChild>
        <Button variant="outline">Open drawer</Button>
      </Drawer.Trigger>
      <Drawer.Content>
        <Drawer.Header>
          <Drawer.Title>Drawer title</Drawer.Title>
          <Drawer.Close asChild>
            <CloseButton />
          </Drawer.Close>
        </Drawer.Header>
        <Drawer.Body>
          <Drawer.Description>
            Drag it down, click the backdrop, press Escape, or use the close
            button to dismiss it.
          </Drawer.Description>
        </Drawer.Body>
      </Drawer.Content>
    </Drawer>
  );
}

Direction

Passing direction ("top" | "right" | "bottom" | "left") to Drawer sets the edge the panel slides from.

tsx

import { Button, CloseButton, Drawer } from "@hummingbirdui/react";

const directions = ["top", "right", "bottom", "left"] as const;

export default function DrawerDirection() {
  return (
    <div className="flex flex-wrap gap-2 justify-center">
      {directions.map((direction) => (
        <Drawer key={direction} direction={direction}>
          <Drawer.Trigger asChild>
            <Button variant="outline" className="capitalize">
              {direction}
            </Button>
          </Drawer.Trigger>
          <Drawer.Content>
            <Drawer.Header>
              <Drawer.Title className="capitalize">
                {direction} drawer
              </Drawer.Title>
              <Drawer.Close asChild>
                <CloseButton />
              </Drawer.Close>
            </Drawer.Header>
            <Drawer.Body>
              <Drawer.Description>
                Slides in from the {direction} edge.
              </Drawer.Description>
            </Drawer.Body>
          </Drawer.Content>
        </Drawer>
      ))}
    </div>
  );
}

Without overlay

Setting overlay={false} on Drawer.Content renders the panel without the backdrop.

tsx

import { Button, CloseButton, Drawer } from "@hummingbirdui/react";

export default function DrawerWithoutOverlay() {
  return (
    <Drawer direction="right">
      <Drawer.Trigger asChild>
        <Button variant="outline">Open without overlay</Button>
      </Drawer.Trigger>
      <Drawer.Content overlay={false}>
        <Drawer.Header>
          <Drawer.Title>No backdrop</Drawer.Title>
          <Drawer.Close asChild>
            <CloseButton />
          </Drawer.Close>
        </Drawer.Header>
        <Drawer.Body>
          <Drawer.Description>
            Setting <code>overlay=&#123;false&#125;</code> hides the backdrop so
            the page behind stays visible.
          </Drawer.Description>
        </Drawer.Body>
      </Drawer.Content>
    </Drawer>
  );
}

Scrollable body

Drawer.Body grows to fill the panel and scrolls its own overflow while the header stays pinned.

tsx

import { Button, CloseButton, Drawer } from "@hummingbirdui/react";

export default function DrawerScrollable() {
  return (
    <Drawer direction="right">
      <Drawer.Trigger asChild>
        <Button variant="outline">Open long drawer</Button>
      </Drawer.Trigger>
      <Drawer.Content>
        <Drawer.Header>
          <Drawer.Title>Terms of service</Drawer.Title>
          <Drawer.Close asChild>
            <CloseButton />
          </Drawer.Close>
        </Drawer.Header>
        <Drawer.Body>
          <p>Scroll to read all of the content below.</p>
          <p>
            Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum
            nec odio. Praesent libero. Sed cursus ante dapibus diam. Sed nisi.
            Nulla quis sem at nibh elementum imperdiet.
          </p>
          <p>
            Duis sagittis ipsum. Praesent mauris. Fusce nec tellus sed augue
            semper porta. Mauris massa. Vestibulum lacinia arcu eget nulla.
          </p>
          <p>
            Class aptent taciti sociosqu ad litora torquent per conubia nostra,
            per inceptos himenaeos. Curabitur sodales ligula in libero.
          </p>
          <p>
            Sed dignissim lacinia nunc. Curabitur tortor. Pellentesque nibh.
            Aenean quam. In scelerisque sem at dolor. Maecenas mattis.
          </p>
        </Drawer.Body>
      </Drawer.Content>
    </Drawer>
  );
}

API Reference

Built on Vaul. Each part forwards all props to its Vaul counterpart, except Drawer.Header and Drawer.Body, which are Hummingbird-specific layout parts rendered as plain div elements.

Drawer

Contains all the parts of a drawer.

PropTypeDefault
defaultOpenbooleanfalse
openboolean
onOpenChangefunction
modalbooleantrue
containerHTMLElementdocument.body
directionenum"bottom"
onAnimationEndfunction
dismissiblebooleantrue
handleOnlybooleanfalse
repositionInputsbooleantrue
snapPointsarray
activeSnapPointnumber | string | null
setActiveSnapPointfunction
fadeFromIndexnumber
snapToSequentialPointbooleanfalse

Drawer.Trigger

The button that opens the drawer.

PropTypeDefault
asChildbooleanfalse
classNamestring

Data attributeValues
[data-state]"open" | "closed"

Drawer.Portal

When used, portals your overlay and content parts into the body. Drawer.Content renders this part automatically, so you rarely need to use it directly.

PropTypeDefault
forceMountboolean
containerHTMLElementdocument.body

Drawer.Overlay

A layer that covers the inert portion of the view when the drawer is open. Drawer.Content renders this part automatically while overlay is true.

PropTypeDefault
asChildbooleanfalse
forceMountboolean
classNamestring

Data attributeValues
[data-state]"open" | "closed"

Drawer.Content

Contains content to be rendered in the open drawer. Always renders its own Drawer.Portal, and shows a drag handle when direction is "bottom".

PropTypeDefault
asChildbooleanfalse
forceMountboolean
onOpenAutoFocusfunction
onCloseAutoFocusfunction
onEscapeKeyDownfunction
onPointerDownOutsidefunction
onInteractOutsidefunction
overlaybooleantrue
classNamestring

Data attributeValues
[data-state]"open" | "closed"
[data-vaul-drawer-direction]"top" | "right" | "bottom" | "left"

Drawer.Header

Hummingbird-specific layout part. Renders a div with the offcanvas-header class for the top area of the drawer.

Drawer.Title

An accessible title to be announced when the drawer is opened. Renders an h6 element by default.

PropTypeDefault
asChildbooleanfalse
classNamestring

Drawer.Description

An optional accessible description to be announced when the drawer is opened.

PropTypeDefault
asChildbooleanfalse
classNamestring

Drawer.Body

Hummingbird-specific layout part. Renders a div with the offcanvas-body class that grows to fill the panel and scrolls its own overflow.

Drawer.Close

The button that closes the drawer.

PropTypeDefault
asChildbooleanfalse
classNamestring

Styling

Hummingbird React drawer is styled entirely through Hummingbird's utility classes and CSS variables.

  • See the full list of available drawer classes in the Class overview.
  • Visit the CSS Variables documentation to explore all available variables.