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>Navigation 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.
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-visibleor[data-focus-visible="true"]- Applied to trigger and close button - Hover:
:hoveror[data-hovered="true"]- Applied to close button on hover - Active:
:activeor[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
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | - | Trigger and backdrop elements |
state | UseOverlayStateReturn | - | Controlled overlay state |
Drawer.Trigger
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | - | Custom trigger content |
className | string | - | CSS classes |
Drawer.Backdrop
| Prop | Type | Default | Description |
|---|---|---|---|
variant | "opaque" | "blur" | "transparent" | "opaque" | Backdrop overlay style |
isDismissable | boolean | true | Close on backdrop click |
isKeyboardDismissDisabled | boolean | false | Disable ESC key to close |
isOpen | boolean | - | Controlled open state |
onOpenChange | (isOpen: boolean) => void | - | Open state change handler |
className | string | (values) => string | - | Backdrop CSS classes |
Drawer.Content
| Prop | Type | Default | Description |
|---|---|---|---|
placement | "top" | "bottom" | "left" | "right" | "bottom" | Edge the drawer slides from |
className | string | (values) => string | - | Content CSS classes |
Drawer.Dialog
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | - | Dialog content |
className | string | - | CSS classes |
role | string | "dialog" | ARIA role |
aria-label | string | - | Accessibility label |
aria-labelledby | string | - | ID of label element |
Drawer.Header
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | - | Header content |
className | string | - | CSS classes |
Drawer.Heading
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | - | Title text |
className | string | - | CSS classes |
Drawer.Body
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | - | Body content |
className | string | - | CSS classes |
Drawer.Footer
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | - | Footer content |
className | string | - | CSS classes |
Drawer.Handle
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | - | CSS classes |
Drawer.CloseTrigger
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | - | Custom close button |
className | string | (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 directlyAccessibility
Implements WAI-ARIA Dialog pattern:
- Focus trap: Focus locked within drawer when open
- Keyboard:
ESCcloses (when dismissable),Tabcycles 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



