---
name: drawer-usage
description: >
Use after component-usage-ux when an app needs @techsio/ui-kit Drawer for
transient edge panels, modal or non-modal behavior, snap points, swipe
gestures, multiple triggers, custom portals, controlled state, and stacks.
metadata:
component_version: "1.0.0"
type: "core"
library: "@techsio/ui-kit"
library_version: "0.3.2"
requires: "component-usage-ux zag-compound-components app-token-overrides ux-guidelines"
sources: "libs/ui/src/molecules/drawer.tsx libs/ui/src/internal/molecules/drawer.context.tsx libs/ui/src/internal/molecules/drawer.styles.ts libs/ui/src/tokens/components/molecules/_drawer.css libs/ui/stories/molecules/drawer.stories.tsx https://zagjs.com/components/react/drawer"
---
# @techsio/ui-kit Drawer Usage
Use Drawer for transient panels that enter from a viewport or container edge.
Use Sidebar for persistent application navigation, Dialog for centered focused
flows, and Popover for anchored contextual content.
## UX/UI guidelines
House rules come from the `ux-guidelines` skill (writing, formatting, states,
where actions and feedback live). This section applies them to `Drawer`.
**Use it when**
- Transient panels that slide from an edge: cart, mobile filters, mobile navigation, quick views.
- Content that relates to the page behind it and should keep that context visible.
**Use something else when**
| Need | Use instead |
| --- | --- |
| Persistent desktop navigation | Sidebar |
| Record create/edit/read in admin | Dialog placement="right" (the CRUD reference pattern) |
| Focused blocking decision | Dialog |
| Anchored small content | Popover |
**Do**
- Open from the edge that matches the content's origin: navigation start, cart/filters/details end.
- Keep a visible title and close button; footer actions bottom-right like dialogs.
- Return focus to the trigger on close; preserve page scroll.
**Don't**
- Stack drawers.
- Use a drawer for long multi-step flows — use a page with Steps.
**Copy and states**
- Title names the content (`Cart (3)`, `Filters`); filter drawers end with `[Reset] [Show 24 results]`.
## Setup
```tsx
import { Drawer } from "@techsio/ui-kit/molecules/drawer"
Open cartCartReview items before checkout.{/* cart content */}Close
```
Supported root props:
```text
placement: start | end | top | bottom
size: xs | sm | md | lg | xl | full
open/defaultOpen, onOpenChange
triggerValue/defaultTriggerValue, onTriggerValueChange
snapPoints, snapPoint/defaultSnapPoint, onSnapPointChange
snapToSequentialPoints, swipeVelocityThreshold, closeThreshold
modal, trapFocus, preventScroll, restoreFocus
closeOnEscape, closeOnInteractOutside, role
ids, dir, getRootNode, initialFocusEl, finalFocusEl
onEscapeKeyDown, onFocusOutside, onInteractOutside, onPointerDownOutside
preventDragOnScroll, swipeVelocityThreshold, closeThreshold
lazyMount, unmountOnExit, immediate, skipAnimationOnMount
onEnterComplete, onExitComplete
```
## Core Patterns
### Preserve the compound anatomy
Keep Backdrop and Positioner inside Portal, then place Content inside
Positioner. Title and Description supply the accessible dialog name and
description. Do not conditionally remove the portal based on `open`; Drawer
coordinates exit presence itself.
### Use placement instead of swipeDirection
`placement` owns both the rendered edge and the closing gesture. `start` and
`end` follow text direction. Root intentionally does not expose
`swipeDirection`; `Drawer.SwipeArea` accepts an optional opening direction.
For a machine-level integration, call the exported `useDrawer` hook with raw
Zag props and provide its result to `Drawer.RootProvider`. This is also the
escape hatch for a custom `swipeDirection` or externally shared machine API.
This advanced surface tracks the exact pinned Zag 1.43.3 machine contract;
prefer the compound root API when raw machine access is unnecessary.
```tsx
const drawer = useDrawer({ swipeDirection: "end", open, onOpenChange })
{/* standard anatomy */}
```
### Add snap points for draggable sheets
Use numeric viewport ratios or CSS lengths such as `"320px"` and `"24rem"`.
Pair snap points with Grabber and GrabberIndicator. Set
`draggable={false}` on Content when dragging should start only from the
grabber.
```tsx
{/* standard anatomy */}
```
### Select content with multiple triggers
Give each `Drawer.Trigger` a stable `value`. Read `api.triggerValue` through
`Drawer.Context` or control it with `triggerValue` and
`onTriggerValueChange`.
### Coordinate nested drawers with Stack
Wrap related roots in `Drawer.Stack`. Nested roots inherit the stack store;
`Drawer.Indent` and `Drawer.IndentBackground` expose optional app-shell depth
effects.
### Scope rendering with Portal
Pass a mounted element ref to `Drawer.Portal container={ref}`. A custom mount
target does not change fixed positioning by itself. Container-scoped panels
must provide an appropriate positioned containing block and override Backdrop
and Positioner positioning together.
### Configure non-modal panels completely
For a panel that permits background interaction, use `modal={false}` together
with `trapFocus={false}` and `preventScroll={false}`. Omit Backdrop when the
background should remain directly interactive.
## Common Mistakes
### HIGH Custom edge panel state
Wrong:
```tsx
{open && }
```
Correct:
```tsx
Open{/* anatomy */}
```
Source: libs/ui/src/molecules/drawer.tsx
### HIGH Conditional unmount bypasses presence
Wrong:
```tsx
{open ? {/* content */} : null}
```
Correct: render the anatomy continuously and use `lazyMount` and
`unmountOnExit` on Drawer.Root.
### HIGH Physical placement in application code
Wrong:
```tsx
```
Correct:
```tsx
```
Source: libs/ui/src/molecules/drawer.tsx
### MEDIUM Non-modal root with modal focus behavior
Wrong:
```tsx
{/* background should remain interactive */}
```
Correct:
```tsx
{/* omit Backdrop when appropriate */}
```
## Validation Commands
```sh
rg -n "fixed.*(left|right|top|bottom)-0|