DialogDropdown Menu
Get Started
Introduction
Components
Accordion
Badge
Button
Card
Checkbox
Command
Dialog
Dropdown Menu
Input
Select
Switch
Table
Tabs
Toast
Tooltip
Forms
Controlled Input
Field Arrays
Submit
Validation

A panel that slides in from the edge of the screen, typically from the bottom. Ideal for mobile-friendly interactions.

top
right
bottom
left

#Installation

bunx --bun barefoot 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/dom'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/dom'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/dom'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

PropTypeDefaultDescription
openbooleanfalseWhether the drawer is open.
onOpenChange(open: boolean) => void-Event handler called when the open state should change.

DrawerTrigger

PropTypeDefaultDescription
disabledbooleanfalseWhether the trigger is disabled.
asChildbooleanfalseRender child element as trigger instead of built-in button.

DrawerContent

PropTypeDefaultDescription
direction'top' | 'right' | 'bottom' | 'left''bottom'Which edge of the screen the drawer slides from.
ariaLabelledbystring-ID of the element that labels the drawer (typically DrawerTitle).
ariaDescribedbystring-ID of the element that describes the drawer (typically DrawerDescription).

DrawerHandle

PropTypeDefaultDescription
classstring-Additional CSS classes for the handle bar.

DrawerTitle

PropTypeDefaultDescription
idstring-ID for aria-labelledby reference.

DrawerDescription

PropTypeDefaultDescription
idstring-ID for aria-describedby reference.

DrawerClose

PropTypeDefaultDescription