# Drawer **Category**: react **URL**: https://www.heroui.com/docs/react/components/drawer **Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/react/components/(overlays)/drawer.mdx > Slide-out panel for supplementary content and actions *** ## Import ```tsx import { Drawer, Button } from "@heroui/react"; ``` ### Usage ```tsx import {Button, Drawer} from "@heroui/react"; export function Basic() { return ( Drawer Title

This is a bottom drawer built with React Aria's Modal component. It slides up from the bottom of the screen with a smooth CSS transition.

); } ``` ### Anatomy ```tsx import { Drawer, Button } from "@heroui/react"; export default () => ( {/* Optional: Drag handle */} {/* Optional: Close button */} ); ``` ### Placement ```tsx import {Button, Drawer} from "@heroui/react"; export function Placements() { const placements = ["bottom", "top", "left", "right"] as const; return (
{placements.map((placement) => ( {placement === "bottom" && } {placement.charAt(0).toUpperCase() + placement.slice(1)} Drawer

This drawer slides in from the {placement} edge of the screen.

{placement === "top" && }
))}
); } ``` ### Backdrop Variants ```tsx import {Button, Drawer} from "@heroui/react"; export function BackdropVariants() { const variants = ["opaque", "blur", "transparent"] as const; return (
{variants.map((variant) => ( Backdrop: {variant.charAt(0).toUpperCase() + variant.slice(1)}

This drawer uses the {variant} backdrop variant.

))}
); } ``` ### 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. ```tsx import {Button, Drawer} from "@heroui/react"; export function NonDismissable() { return ( Confirm Action

This drawer cannot be dismissed by clicking outside or dragging. You must use one of the buttons below.

); } ``` ### Scrollable Content The `Drawer.Body` automatically handles overflow with native scrolling. Drag-to-dismiss is excluded from the body area to avoid scroll conflicts. ```tsx import {Button, Drawer} from "@heroui/react"; export function ScrollableContent() { return ( Terms & Conditions {Array.from({length: 20}).map((_, i) => (

Paragraph {i + 1}: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam pulvinar risus non risus hendrerit venenatis. Pellentesque sit amet hendrerit risus, sed porttitor quam.

))}
); } ``` ### Controlled State ```tsx "use client"; import {Button, Drawer, useOverlayState} from "@heroui/react"; import React from "react"; export function Controlled() { const [isOpen, setIsOpen] = React.useState(false); const state = useOverlayState(); return (

With React.useState()

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

Status:{" "} {isOpen ? "open" : "closed"}

Controlled with useState()

This drawer is controlled by React's useState hook. Pass{" "} isOpen and onOpenChange props to manage the drawer state externally.

With useOverlayState()

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

Status:{" "} {state.isOpen ? "open" : "closed"}

Controlled with useOverlayState()

The useOverlayState hook provides dedicated methods for common operations. No need to manually create callbacks—just use{" "} state.open(), state.close(), or{" "} state.toggle().

); } ``` ### With Form ```tsx import {Button, Drawer, Input, Label, TextField} from "@heroui/react"; export function WithForm() { return ( Edit Profile
); } ``` ### Navigation Drawer ```tsx import type {ComponentType, SVGProps} from "react"; import {Bars, Bell, Envelope, Gear, House, Magnifier, Person} from "@gravity-ui/icons"; import {Button, Drawer} from "@heroui/react"; export function Navigation() { const navItems: {icon: ComponentType>; label: string}[] = [ {icon: House, label: "Home"}, {icon: Magnifier, label: "Search"}, {icon: Bell, label: "Notifications"}, {icon: Envelope, label: "Messages"}, {icon: Person, label: "Profile"}, {icon: Gear, label: "Settings"}, ]; return ( Navigation ); } ``` ## Related Components - **Modal**: Displays content in a modal overlay - **Button**: Allows a user to perform an action - **CloseButton**: Button for dismissing overlays ## Styling ### Passing Tailwind CSS classes ```tsx import { Drawer, Button } from "@heroui/react"; function CustomDrawer() { return ( Custom Styled Drawer

This drawer has custom styling applied via Tailwind classes.

); } ``` ### Customizing the component classes To customize the Drawer component classes, you can use the `@layer components` directive.
[Learn more](https://tailwindcss.com/docs/adding-custom-styles#adding-component-classes). ```css @layer components { .drawer__backdrop { @apply bg-gradient-to-br from-black/50 to-black/70; } .drawer__dialog { @apply rounded-2xl border border-white/10 shadow-2xl; } .drawer__header { @apply text-center; } .drawer__close-trigger { @apply rounded-full bg-white/10 hover:bg-white/20; } } ``` HeroUI follows the [BEM](https://getbem.com/) 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](https://github.com/heroui-inc/heroui/blob/v3/packages/styles/components/drawer.css)): #### 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 | 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 ```tsx import { useOverlayState } from "@heroui/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](https://www.w3.org/WAI/ARIA/apg/patterns/dialog-modal/): - **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