Drawer

The Drawer component is a panel that slides out from the edge of the screen. It can be useful when you need users to complete a task or view some details without leaving the current page.

Import

import {
		Drawer,
		DrawerTrigger,
		DrawerContent,
		DrawerHeading,
		DrawerFooter,
		DrawerBody,
		DrawerCloseButton
} from "@recastui/react";

Usage

Editable Example
<Drawer>
<DrawerTrigger asChild>
<Button>Open Drawer</Button>
</DrawerTrigger>
<DrawerContent>
<DrawerHeading>Drawer Title</DrawerHeading>
<DrawerCloseButton />
<DrawerBody>
Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
</DrawerBody>
<DrawerFooter>
<div className='space-x-3'>
<Button size='sm'>
Main Action
</Button>
<Button size='sm' variant='ghost'>Secondary Action</Button>
</div>
</DrawerFooter>
</DrawerContent>
</Drawer>

Drawer placement positions

The Drawer can appear from any edge of the screen. Pass the position prop and set it to top, right, bottom, or left. Defalut is left.

Editable Example
() => {
const [isOpen, setIsOpen] = useState(false);
const [position, setPosition] = useState('left');
const handlePositionClick = (newPosition) => {
setPosition(newPosition);
setIsOpen(true);
};
const positions = ['left', 'right', 'top', 'bottom'];
return (
<>
<div className='grid gap-2 grid-cols-2'>
{positions.map((p) => (
<Button
onClick={() => handlePositionClick(p)}
key={p}
>{`Open ${p} Drawer`}</Button>
))}
</div>
<Drawer open={isOpen} onOpenChange={setIsOpen} position={position}>
<DrawerContent>
<DrawerHeading>Drawer Title</DrawerHeading>
<DrawerCloseButton />
<DrawerBody>
Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
</DrawerBody>
<DrawerFooter>
<div className='space-x-3'>
<Button onClick={()=>setIsOpen(false)}>
Close
</Button>
<Button variant='ghost'>Secondary Action</Button>
</div>
</DrawerFooter>
</DrawerContent>
</Drawer>
</>);
}

Drawer sizes

Pass the size prop if you need to adjust the size of the Drawer. Values can be xs, sm, md, lg, xl, or full. Default is xs.

Editable Example
() => {
const [isOpen, setIsOpen] = useState(false);
const [size, setSize] = useState('xs');
const handleSizeClick = (newSize) => {
setSize(newSize);
setIsOpen(true);
};
const sizes = ['xs', 'sm', 'md', 'lg', 'xl', 'full'];
return (
<>
<div className='grid gap-2 grid-cols-3'>
{sizes.map((s) => (
<Button
onClick={() => handleSizeClick(s)}
key={s}
>{`Open ${s} Drawer`}</Button>
))}
</div>
<Drawer open={isOpen} onOpenChange={setIsOpen} size={size}>
<DrawerContent>
<DrawerHeading>Drawer Title</DrawerHeading>
<DrawerCloseButton />
<DrawerBody>
Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
</DrawerBody>
<DrawerFooter>
<div className='space-x-3'>
<Button onClick={()=>setIsOpen(false)}>
Close
</Button>
<Button variant='ghost'>Secondary Action</Button>
</div>
</DrawerFooter>
</DrawerContent>
</Drawer>
</>);
}

Focus on specific element

When a form is in the drawer, you might need to set focus on a specific element when the drawer opens. Pass the initialFocusRef prop.

Without the initialFocusRef prop, the drawer will set focus on the first focusable element when it opens.

Editable Example
() => {
const [isOpen, setIsOpen] = useState(false);
const initialRef = React.useRef(null);
return (
<>
<Button onClick={()=>setIsOpen(true)}>Show Drawer</Button>
<Drawer initialFocus={initialRef} open={isOpen} onOpenChange={setIsOpen}>
<DrawerContent>
<DrawerHeading>Drawer Title</DrawerHeading>
<DrawerCloseButton />
<DrawerBody>
<Button ref={initialRef}>This button has initial Focus</Button>
Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
</DrawerBody>
<DrawerFooter>
<div className='space-x-3'>
<Button onClick={()=>setIsOpen(false)}>
Close
</Button>
<Button variant='ghost'>Secondary Action</Button>
</div>
</DrawerFooter>
</DrawerContent>
</Drawer>
</>
);
}

Props

Drawer

PropTypeDefaultDescription
initialOpenbooleanfalseThe initial open state of the Modal (optional).
openboolean-The open state of the Modal in controlled mode.
onOpenChange(open: boolean) => void-A callback function for handling open state changes in controlled mode.
initialFocusReact.RefObject<HTMLElement>-Ref to the initial element to focus when the modal opens.
returnFocusbooleantrueReturn focus to the element that triggered modal to open when the modal closes.
size“xs” | “sm” | “md” | “lg” | “xl” | “full”“md”The size of the modal.
position“left” | “right” | “top” | “bottom”“left”The placement position of the drawer.
childrenReact.ReactNode-Children passed to the subcomponents.
classNamestring (optional)-Additional class names to apply

DrawerContent

PropTypeDefaultDescription
classNamestring (optional)-Additional class names to apply
overlayClassNamestring (optional)-Additional class names to apply to the Overlay element
childrenReact.ReactNode-Children passed to the component.

DrawerTrigger

PropTypeDefaultDescription
asChildbooleanfalseChildren passed to the component.
classNamestring (optional)-Additional class names to apply
childrenReact.ReactNode-Children passed to the component.

DrawerTrigger, DrawerHeading, DrawerBody, DrawerFooter & DrawerCloseButton

PropTypeDescription
childrenReact.ReactNodeThe children for the subcomponents
classNamestring (optional)Additional class names to apply

Accessibility

This Drawer component has been designed to follow best practices for accessibility:

  • Focus is trapped within the drawer when it is open.
  • Focus is automatically set to the first enabled element or the element specified by initialFocus.
  • When the drawer closes, focus returns to the element that was focused before the drawer was activated, or the element specified by finalFocusRef.
  • Clicking on the overlay closes the drawer.
  • Pressing the Esc key closes the drawer.
  • Scrolling is blocked on the elements behind the drawer.
  • The drawer is rendered in a portal attached to the end of document.body, making it easy to add aria-hidden to its siblings.
  • aria-modal is set to true on the DrawerContent component.
  • aria-labelledby is set to the id of the DrawerHeading component.
  • aria-describedby is set to the id of the DrawerBody component.
Previous
Checkbox