The Drawer component provides a slide-out navigation panel, commonly used for app-wide navigation menus. Import it from one/drawer to keep the bundle size minimal when not using the drawer.
This component should only be rendered inside a _layout.tsx file, where it will serve as the location that children will render for routes below the layout.
Drawer wraps React Navigation’s Drawer Navigator and accepts the same props.
import { GestureHandlerRootView } from 'react-native-gesture-handler'import { Drawer } from 'one/drawer'
export default function Layout() { return ( <GestureHandlerRootView style={{ flex: 1 }}> <Drawer /> </GestureHandlerRootView> )}GestureHandlerRootView wrapper is required for gesture handling to work properly on native platforms.You can customize the drawer appearance and behavior using screenOptions:
import { GestureHandlerRootView } from 'react-native-gesture-handler'import { Drawer } from 'one/drawer'
export default function Layout() { return ( <GestureHandlerRootView style={{ flex: 1 }}> <Drawer screenOptions={{ headerShown: true, drawerType: 'front', // improve swipe gesture feel swipeEdgeWidth: 80, swipeMinDistance: 20, }} > <Drawer.Screen name="index" options={{ drawerLabel: 'Home', title: 'Home', }} /> <Drawer.Screen name="settings" options={{ drawerLabel: 'Settings', title: 'Settings', }} /> </Drawer> </GestureHandlerRootView> )}You can open and close the drawer programmatically using navigation:
import { useNavigation, DrawerActions } from '@react-navigation/native'
function MyScreen() { const navigation = useNavigation()
return ( <Button onPress={() => navigation.dispatch(DrawerActions.openDrawer())} title="Open Drawer" /> )}The drawerType option controls how the drawer appears:
'front' (default) - Drawer slides over the content'back' - Content slides to reveal drawer behind'slide' - Both drawer and content slide together'permanent' - Drawer is always visible (good for tablets)| Option | Type | Default | Description |
|---|---|---|---|
drawerType | 'front' | 'back' | 'slide' | 'permanent' | 'front' | How the drawer animates |
swipeEdgeWidth | number | 32 | Width of the swipe area from screen edge |
swipeMinDistance | number | 60 | Minimum swipe distance to open drawer |
swipeEnabled | boolean | true | Enable/disable swipe gestures |
drawerPosition | 'left' | 'right' | 'left' | Which side the drawer appears |
headerShown | boolean | true | Show/hide the header |
On web, <Drawer> renders headless: only the focused screen, no sidebar. Open state lives in navigation state - drive your own sidebar with useDrawer, which gives you the screen list, the focused screen, isOpen, and open/close/toggle actions:
import { Drawer } from 'one/drawer'import { Link, useDrawer } from 'one'
function WebDrawerLayout() { const { screens, focused, isOpen, close, toggle } = useDrawer()
return ( <> <button onClick={toggle}>Menu</button>
{isOpen && ( <nav> {screens.map((screen) => ( <Link key={screen.key} href={screen.href} onPress={close}> {screen.options.drawerLabel ?? screen.options.title ?? screen.name} </Link> ))} </nav> )}
{focused.element} </> )}
export default function Layout() { return ( <Drawer> <Drawer.Screen name="index" options={{ drawerLabel: 'Home' }} /> <Drawer.Screen name="settings" options={{ drawerLabel: 'Settings' }} /> <WebDrawerLayout /> </Drawer> )}A component placed as a child of <Drawer> replaces the headless default on web and is ignored on native. See the headless web navigators guide for more.
The Drawer requires these optional peer dependencies to be installed:
npm install @react-navigation/drawer react-native-gesture-handler react-native-reanimatedThese are marked as optional peer dependencies in one, so they won’t be installed automatically. This keeps bundle sizes smaller for apps that don’t use the Drawer.
For more configuration options, see the React Navigation Drawer documentation.
Edit this page on GitHub.