Overlays

Drawer

Slide-out panel for supplementary content and actions

Completeness: behavior-required

The stylesheet is only the visible half of this component. It also needs a keyboard map, focus managed across more than one element, ARIA attributes that point at other nodes, and [data-*] attributes that only running code sets — so a CSS-only port will not reproduce it. Use @blakeui/react, or read the interaction contract from the MCP server with get_component_behavior("Drawer") and build the behaviour yourself.

Import

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

Usage

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

export function Basic() {
  return (
    <Drawer>

Anatomy

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

export default () => (
  <Drawer>
    <Button>Open Drawer</Button>
    <Drawer.Backdrop>
      <Drawer.Content>
        <Drawer.Dialog>
          <Drawer.Handle /> {/* Optional: Drag handle */}
          <Drawer.CloseTrigger /> {/* Optional: Close button */}
          <Drawer.Header>
            <Drawer.Heading />
          </Drawer.Header>
          <Drawer.Body />
          <Drawer.Footer />
        </Drawer.Dialog>
      </Drawer.Content>
    </Drawer.Backdrop>
  </Drawer>
);

Placement

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

export function Placements() {
  const placements = ["bottom", "top", "left", "right"] as const;

Backdrop Variants

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

export function BackdropVariants() {
  const variants = ["opaque", "blur", "transparent"] as const;

Non-Dismissable

Set isDismissable={false} on Drawer.Backdrop to prevent closing by clicking outside or dragging. The user must interact with the drawer's action buttons.

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

export function NonDismissable() {
  return (
    <Drawer>

Scrollable Content

The Drawer.Body automatically handles overflow with native scrolling. Drag-to-dismiss is excluded from the body area to avoid scroll conflicts.

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

export function ScrollableContent() {
  return (
    <Drawer>

Controlled State

With React.useState()

Control the drawer using React's useState hook for simple state management.

Status: closed

With useOverlayState()

Use the useOverlayState hook for a cleaner API with convenient methods like open(), close(), and toggle().

Status: closed

"use client";

import {Button, Drawer, useOverlayState} from "@blakeui/react";
import React from "react";

With Form

import {Button, Drawer, Input, Label, TextField} from "@blakeui/react";

export function WithForm() {
  return (
    <Drawer>
import type {ComponentType, SVGProps} from "react";

import {Button, Drawer} from "@blakeui/react";
import {Bars, Bell, Envelope, Gear, House, Magnifier, Person} from "@gravity-ui/icons";

Styling

Passing Tailwind CSS classes

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

function CustomDrawer() {
  return (
    <Drawer>
      <Button>Open Drawer</Button>
      <Drawer.Backdrop className="bg-black/80">
        <Drawer.Content>
          <Drawer.Dialog className="bg-linear-to-br from-purple-500 to-pink-500 text-white">
            <Drawer.CloseTrigger />
            <Drawer.Header>
              <Drawer.Heading>Custom Styled Drawer</Drawer.Heading>
            </Drawer.Header>
            <Drawer.Body>
              <p>This drawer has custom styling applied via Tailwind classes.</p>
            </Drawer.Body>
            <Drawer.Footer>
              <Button slot="close">Close</Button>
            </Drawer.Footer>
          </Drawer.Dialog>
        </Drawer.Content>
      </Drawer.Backdrop>
    </Drawer>
  );
}

Customizing the component classes

To customize the Drawer component classes, you can use the @layer components directive.


Learn more.

A worked example is in Styling.

blakeUI follows the BEM methodology to ensure component variants and states are reusable and easy to customize.

CSS Classes

The Drawer component uses these CSS classes (View source styles):

Base Classes

  • .drawer__trigger - Trigger element that opens the drawer
  • .drawer__backdrop - Overlay backdrop behind the drawer
  • .drawer__content - Positioning wrapper for the drawer panel
  • .drawer__dialog - The drawer panel itself
  • .drawer__header - Header section for titles
  • .drawer__heading - Main title text
  • .drawer__body - Main scrollable content area
  • .drawer__footer - Footer section for actions
  • .drawer__handle - Visual drag handle indicator
  • .drawer__close-trigger - Close button element

Backdrop Variants

  • .drawer__backdrop--opaque - Opaque colored backdrop (default)
  • .drawer__backdrop--blur - Blurred backdrop with glass effect
  • .drawer__backdrop--transparent - Transparent backdrop (no overlay)

Placement Variants

  • .drawer__content--bottom - Slides up from the bottom edge (default)
  • .drawer__content--top - Slides down from the top edge
  • .drawer__content--left - Slides in from the left edge
  • .drawer__content--right - Slides in from the right edge

Dialog Variants

  • .drawer__dialog--top - Slides down from the top edge
  • .drawer__dialog--bottom - Slides up from the bottom edge
  • .drawer__dialog--left - Slides in from the left edge
  • .drawer__dialog--right - Slides in from the right edge

Interactive States

The component supports these interactive states:

  • Focus: :focus-visible or [data-focus-visible="true"] - Applied to trigger and close button
  • Hover: :hover or [data-hovered="true"] - Applied to close button on hover
  • Active: :active or [data-pressed="true"] - Applied to trigger and close button when pressed
  • Entering: [data-entering] - Applied during drawer opening animation
  • Exiting: [data-exiting] - Applied during drawer closing animation
  • Placement: [data-placement="*"] - Applied based on drawer position (top, bottom, left, right)

API Reference

Drawer

PropTypeDefaultDescription
childrenReactNode-Trigger and backdrop elements
stateUseOverlayStateReturn-Controlled overlay state

Drawer.Trigger

PropTypeDefaultDescription
childrenReactNode-Custom trigger content
classNamestring-CSS classes

Drawer.Backdrop

PropTypeDefaultDescription
variant"opaque" | "blur" | "transparent""opaque"Backdrop overlay style
isDismissablebooleantrueClose on backdrop click
isKeyboardDismissDisabledbooleanfalseDisable ESC key to close
isOpenboolean-Controlled open state
onOpenChange(isOpen: boolean) => void-Open state change handler
classNamestring | (values) => string-Backdrop CSS classes

Drawer.Content

PropTypeDefaultDescription
placement"top" | "bottom" | "left" | "right""bottom"Edge the drawer slides from
classNamestring | (values) => string-Content CSS classes

Drawer.Dialog

PropTypeDefaultDescription
childrenReactNode-Dialog content
classNamestring-CSS classes
rolestring"dialog"ARIA role
aria-labelstring-Accessibility label
aria-labelledbystring-ID of label element

Drawer.Header

PropTypeDefaultDescription
childrenReactNode-Header content
classNamestring-CSS classes

Drawer.Heading

PropTypeDefaultDescription
childrenReactNode-Title text
classNamestring-CSS classes

Drawer.Body

PropTypeDefaultDescription
childrenReactNode-Body content
classNamestring-CSS classes

Drawer.Footer

PropTypeDefaultDescription
childrenReactNode-Footer content
classNamestring-CSS classes

Drawer.Handle

PropTypeDefaultDescription
classNamestring-CSS classes

Drawer.CloseTrigger

PropTypeDefaultDescription
childrenReactNode-Custom close button
classNamestring | (values) => string-CSS classes

useOverlayState Hook

import { useOverlayState } from "@blakeui/react";

const state = useOverlayState({
  defaultOpen: false,
  onOpenChange: (isOpen) => console.log(isOpen),
});

state.isOpen; // Current state
state.open(); // Open drawer
state.close(); // Close drawer
state.toggle(); // Toggle state
state.setOpen(); // Set state directly

Accessibility

Implements WAI-ARIA Dialog pattern:

  • Focus trap: Focus locked within drawer when open
  • Keyboard: ESC closes (when dismissable), Tab cycles elements
  • Screen readers: Proper ARIA attributes via React Aria
  • Scroll lock: Body scroll disabled when open
  • Drag to dismiss: Supports pointer-based drag gestures on handle, header, and footer areas

On this page