Drawer
A panel that slides in from the edge of the screen, typically from the bottom. Ideal for mobile-friendly interactions.
#Installation
npx @barefootjs/cli add drawer#Usage
1import {2 Drawer,3 DrawerTrigger,4 DrawerOverlay,5 DrawerContent,6 DrawerHandle,7 DrawerHeader,8 DrawerTitle,9 DrawerDescription,10 DrawerFooter,11 DrawerClose,12} from '@/components/ui/drawer'#Examples
#Basic
1"use client"23import { createSignal } from '@barefootjs/client'4import {5 Drawer,6 DrawerTrigger,7 DrawerOverlay,8 DrawerContent,9 DrawerHandle,10 DrawerHeader,11 DrawerTitle,12 DrawerDescription,13 DrawerFooter,14 DrawerClose,15} from '@/components/ui/drawer'1617function BasicDrawer() {18 const [open, setOpen] = createSignal(false)1920 return (21 <Drawer open={open()} onOpenChange={setOpen}>22 <DrawerTrigger>Open Drawer</DrawerTrigger>23 <DrawerOverlay />24 <DrawerContent25 direction="bottom"26 ariaLabelledby="drawer-title"27 ariaDescribedby="drawer-description"28 >29 <DrawerHandle />30 <DrawerHeader>31 <DrawerTitle id="drawer-title">Move Goal</DrawerTitle>32 <DrawerDescription id="drawer-description">33 Set your daily move goal.34 </DrawerDescription>35 </DrawerHeader>36 <div className="p-4 pb-0">37 <div className="flex items-center justify-center space-x-2">38 <span className="text-7xl font-bold tracking-tighter">350</span>39 <span className="text-muted-foreground text-sm pb-2">kcal/day</span>40 </div>41 </div>42 <DrawerFooter>43 <DrawerClose>Cancel</DrawerClose>44 </DrawerFooter>45 </DrawerContent>46 </Drawer>47 )48}#Direction
1"use client"23import { createSignal } from '@barefootjs/client'4import {5 Drawer,6 DrawerTrigger,7 DrawerOverlay,8 DrawerContent,9 DrawerHandle,10 DrawerHeader,11 DrawerTitle,12 DrawerDescription,13 DrawerFooter,14 DrawerClose,15} from '@/components/ui/drawer'1617function DrawerDirections() {18 const [openBottom, setOpenBottom] = createSignal(false)1920 return (21 <div className="flex flex-wrap gap-2">22 <Drawer open={openBottom()} onOpenChange={setOpenBottom}>23 <DrawerTrigger>Bottom</DrawerTrigger>24 <DrawerOverlay />25 <DrawerContent direction="bottom" ariaLabelledby="bottom-title">26 <DrawerHandle />27 <DrawerHeader>28 <DrawerTitle id="bottom-title">Bottom Drawer</DrawerTitle>29 <DrawerDescription>Slides from the bottom.</DrawerDescription>30 </DrawerHeader>31 <DrawerFooter>32 <DrawerClose>Close</DrawerClose>33 </DrawerFooter>34 </DrawerContent>35 </Drawer>3637 {/* Repeat for top, right, left with direction="top|right|left" */}38 </div>39 )40}#Form
1"use client"23import { createSignal } from '@barefootjs/client'4import {5 Drawer,6 DrawerTrigger,7 DrawerOverlay,8 DrawerContent,9 DrawerHandle,10 DrawerHeader,11 DrawerTitle,12 DrawerDescription,13 DrawerFooter,14 DrawerClose,15} from '@/components/ui/drawer'1617function GoalDrawer() {18 const [open, setOpen] = createSignal(false)19 const [goal, setGoal] = createSignal(350)20 const adjustGoal = (amount) => {21 setGoal((prev) => Math.max(100, prev + amount))22 }2324 return (25 <Drawer open={open()} onOpenChange={setOpen}>26 <DrawerTrigger>Set Goal</DrawerTrigger>27 <DrawerOverlay />28 <DrawerContent29 direction="bottom"30 ariaLabelledby="form-title"31 ariaDescribedby="form-description"32 >33 <DrawerHandle />34 <DrawerHeader>35 <DrawerTitle id="form-title">Move Goal</DrawerTitle>36 <DrawerDescription id="form-description">37 Set your daily activity goal.38 </DrawerDescription>39 </DrawerHeader>40 <div className="p-4 pb-0">41 <div className="flex items-center justify-center space-x-4">42 <button onClick={() => adjustGoal(-10)}>-</button>43 <span className="text-7xl font-bold">{goal()}</span>44 <button onClick={() => adjustGoal(10)}>+</button>45 </div>46 <p className="text-muted-foreground text-sm text-center mt-1">kcal/day</p>47 </div>48 <DrawerFooter>49 <DrawerClose>Submit</DrawerClose>50 <DrawerClose>Cancel</DrawerClose>51 </DrawerFooter>52 </DrawerContent>53 </Drawer>54 )55}#Accessibility
- Keyboard Navigation - ESC to close, Tab/Shift+Tab cycles within the drawer (focus trap)
- ARIA - role="dialog", aria-modal="true", aria-labelledby, aria-describedby
- Overlay Dismiss - Clicking outside the drawer closes it
- Screen Readers - State changes are announced via data-state attribute
#API Reference
Drawer
| Prop | Type | Default | Description |
|---|---|---|---|
| open | boolean | false | Whether the drawer is open. |
| onOpenChange | (open: boolean) => void | - | Event handler called when the open state should change. |
DrawerTrigger
| Prop | Type | Default | Description |
|---|---|---|---|
| disabled | boolean | false | Whether the trigger is disabled. |
| asChild | boolean | false | Render child element as trigger instead of built-in button. |
DrawerContent
| Prop | Type | Default | Description |
|---|---|---|---|
| direction | 'top' | 'right' | 'bottom' | 'left' | 'bottom' | Which edge of the screen the drawer slides from. |
| ariaLabelledby | string | - | ID of the element that labels the drawer (typically DrawerTitle). |
| ariaDescribedby | string | - | ID of the element that describes the drawer (typically DrawerDescription). |
DrawerHandle
| Prop | Type | Default | Description |
|---|---|---|---|
| class | string | - | Additional CSS classes for the handle bar. |
DrawerTitle
| Prop | Type | Default | Description |
|---|---|---|---|
| id | string | - | ID for aria-labelledby reference. |
DrawerDescription
| Prop | Type | Default | Description |
|---|---|---|---|
| id | string | - | ID for aria-describedby reference. |
DrawerClose
| Prop | Type | Default | Description |
|---|