Skip to content

Commit eb2e7ab

Browse files
committed
docs(changeset): update documentation for Drawer component
1 parent 85ca707 commit eb2e7ab

File tree

1 file changed

+183
-0
lines changed

1 file changed

+183
-0
lines changed

apps/website/docs/drawer.mdx

Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
---
2+
title: "Drawer"
3+
description: "Create a fast bottom sheet drawer that slides from the bottom, supports snapping to multiple positions, and works the same on iOS, Android, and Web."
4+
---
5+
6+
---
7+
8+
## Preview
9+
10+
<Preview component="drawer" title="Interactive Demo" />
11+
12+
---
13+
14+
## Installation
15+
16+
<InstallTabs />
17+
18+
---
19+
20+
## Overview
21+
22+
Drawer is a cross-platform primitive that mounts an overlay at the root of your app and animates a sheet from the bottom of the screen. It supports:
23+
24+
| Feature | Description | Platforms |
25+
| -------------------- | --------------------------------------------------- | ----------------- |
26+
| **Portal-based** | Renders using the Portal primitive | iOS, Android, Web |
27+
| **Snap Points** | Provide percentage or pixel based snap points | iOS, Android, Web |
28+
| **Gestures** | Drag to resize / dismiss with native performance | iOS, Android, Web |
29+
| **Controlled mode** | Manage `open` state externally via props | iOS, Android, Web |
30+
| **Keyboard aware** | Optional `KeyboardAvoidingView` integration on iOS | iOS, Android, Web |
31+
32+
---
33+
34+
## Usage
35+
36+
### 1. Basic Drawer
37+
38+
```tsx
39+
import {
40+
Drawer,
41+
DrawerOverlay,
42+
DrawerContent,
43+
DrawerHandle,
44+
} from "@native-ui-org/primitives";
45+
46+
function Example() {
47+
return (
48+
<Drawer defaultOpen snapPoints={[0.4, 0.7]}>
49+
<DrawerOverlay />
50+
<DrawerContent>
51+
<DrawerHandle />
52+
<View style={{ padding: 24 }}>
53+
<Text style={{ fontSize: 18, fontWeight: "600" }}>Bottom Sheet</Text>
54+
<Text style={{ color: "#555", marginTop: 8 }}>
55+
Drag the handle or tap outside to dismiss.
56+
</Text>
57+
</View>
58+
</DrawerContent>
59+
</Drawer>
60+
);
61+
}
62+
```
63+
64+
### 2. Controlled Drawer
65+
66+
```tsx
67+
function Controlled() {
68+
const [open, setOpen] = React.useState(false);
69+
70+
return (
71+
<>
72+
<Pressable onPress={() => setOpen(true)}>
73+
<Text>Open drawer</Text>
74+
</Pressable>
75+
76+
<Drawer
77+
open={open}
78+
onOpenChange={setOpen}
79+
snapPoints={[0.35, 0.6, 0.9]}
80+
initialSnapIndex={1}
81+
>
82+
<DrawerOverlay />
83+
<DrawerContent>
84+
<DrawerHandle />
85+
<ScrollView style={{ padding: 24 }}>
86+
<Text style={{ fontWeight: "600", fontSize: 18 }}>Controlled drawer</Text>
87+
<Text style={{ color: "#555", marginTop: 12 }}>
88+
The parent decides when we open or close.
89+
</Text>
90+
</ScrollView>
91+
</DrawerContent>
92+
</Drawer>
93+
</>
94+
);
95+
}
96+
```
97+
98+
### 3. Non-resizable drawer
99+
100+
```tsx
101+
<Drawer resizable={false} snapPoints={[0.5]}>
102+
<DrawerOverlay />
103+
<DrawerContent>
104+
<View style={{ padding: 24 }}>
105+
<Text>This drawer cannot be resized.</Text>
106+
</View>
107+
</DrawerContent>
108+
</Drawer>
109+
```
110+
111+
---
112+
113+
## Props
114+
115+
### `Drawer`
116+
117+
| Prop | Type | Default | Description |
118+
| ------------------- | --------------------------------------- | ------------ | --------------------------------------------------------------------------- |
119+
| `open` | `boolean` || Controlled open state. |
120+
| `defaultOpen` | `boolean` | `false` | Initial open state (uncontrolled). |
121+
| `onOpenChange` | `(open: boolean) => void` || Called when drawer requests a state change (close gesture, overlay tap…). |
122+
| `snapPoints` | `number[]` | `[0.5]` | Heights for the sheet. Percentages `0-1` or pixel values. |
123+
| `initialSnapIndex` | `number` | `0` | Index of the snap point to use when opening. |
124+
| `dismissible` | `boolean` | `true` | Allow tapping the overlay or dragging past the threshold to close. |
125+
| `resizable` | `boolean` | `true` | Enable drag gestures on the sheet. |
126+
| `overlayOpacity` | `number` | `0.45` | Target opacity for the backdrop when opened. |
127+
| `keyboardBehavior` | `'padding' | 'height' | 'position' | 'none'` | `padding` on iOS | Behavior passed to `KeyboardAvoidingView`. Uses `height` on Android. |
128+
| `keyboardOffset` | `number` | `0` | Offset applied to `KeyboardAvoidingView`. |
129+
| `portal` | `boolean` | `true` | Render inside the `Portal` primitive. Set to `false` to inline render. |
130+
131+
### `DrawerContent`
132+
133+
| Prop | Type | Default | Description |
134+
| -------- | ----------- | ------- | ------------------------------------------------------------- |
135+
| `asChild`| `boolean` | `false` | Use the Slot pattern and merge props into the child element. |
136+
137+
The content automatically receives the pan handlers. Apply your own padding/layout.
138+
139+
### `DrawerHandle`
140+
141+
| Prop | Type | Default | Description |
142+
| -------- | ----------- | ------- | ------------------------------------------------------------- |
143+
| `asChild`| `boolean` | `false` | Render the handle as a custom component via Slot. |
144+
145+
Children default to a simple pill indicator if none are provided.
146+
147+
### `DrawerOverlay`
148+
149+
| Prop | Type | Default | Description |
150+
| ------------ | --------- | ------- | -------------------------------------------------------- |
151+
| `dismissible`| `boolean` | `true` | Whether tapping the overlay should request closing. |
152+
| `style` | `StyleProp<ViewStyle>` || Additional styles for the animated overlay view. |
153+
154+
---
155+
156+
## Gestures & Snap Points
157+
158+
- Snap points can be declared as percentages (`0.3` = 30% height) or pixels (`320`).
159+
- The sheet animates with native springs and clamps to the nearest snap point on release.
160+
- If `dismissible` is `true`, dragging beyond ~90px from the bottom or flicking down quickly closes the drawer.
161+
- Set `resizable={false}` to disable drag gestures entirely.
162+
163+
---
164+
165+
## Accessibility
166+
167+
- The overlay receives `accessibilityRole="button"` when dismissible so screen readers can close it.
168+
- The content container uses `accessibilityRole="dialog"` and `aria-modal` on web.
169+
- Focus management is left to the consumer (e.g. move focus inside the sheet when opening).
170+
171+
---
172+
173+
## Tips
174+
175+
- Use the `portal={false}` prop to embed the drawer inside another Portal or custom layout.
176+
- Combine with `KeyboardAvoidingView` props on iOS when showing large forms.
177+
- You can read the drawer state using the `useDrawer()` hook inside children for custom controls. (Returns `open`, `close`, `setSnapIndex`, etc.)
178+
179+
---
180+
181+
The Drawer primitive gives you a polished bottom sheet experience with a minimal, composable API and native-feeling performance everywhere.
182+
183+

0 commit comments

Comments
 (0)