<Drawer />

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.

Basic Usage

_layout.tsx

import { GestureHandlerRootView } from 'react-native-gesture-handler'
import { Drawer } from 'one/drawer'
export default function Layout() {
return (
<GestureHandlerRootView style={{ flex: 1 }}>
<Drawer />
</GestureHandlerRootView>
)
}
The GestureHandlerRootView wrapper is required for gesture handling to work properly on native platforms.

With Screen Options

You can customize the drawer appearance and behavior using screenOptions:

_layout.tsx

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>
)
}

Programmatic Control

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" />
)
}

Drawer Types

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)

Common Options

OptionTypeDefaultDescription
drawerType'front' | 'back' | 'slide' | 'permanent''front'How the drawer animates
swipeEdgeWidthnumber32Width of the swipe area from screen edge
swipeMinDistancenumber60Minimum swipe distance to open drawer
swipeEnabledbooleantrueEnable/disable swipe gestures
drawerPosition'left' | 'right''left'Which side the drawer appears
headerShownbooleantrueShow/hide the header

Custom sidebar with render

new

The render prop swaps the default drawer sidebar for a component you control. Useful for branded navigation, a sidebar that doubles as a search palette, or a different UI per platform.

import { Drawer, type DrawerRender } from 'one/drawer'
import { View, Pressable, Text } from 'react-native'
// Hoist outside the layout for stable identity.
const render: DrawerRender = {
web: ({ state, descriptors, navigation }) => (
<View style={{ flex: 1, padding: 16 }}>
{state.routes.map((route, index) => {
const { options } = descriptors[route.key]
const focused = state.index === index
return (
<Pressable key={route.key} onPress={() => navigation.navigate(route.name)} style={{ paddingVertical: 12, opacity: focused ? 1 : 0.6 }} >
<Text>{options.drawerLabel ?? options.title ?? route.name}</Text>
</Pressable>
)
})}
</View>
),
}
export default function Layout() {
return (
<Drawer render={render}>
<Drawer.Screen name="index" options={{ drawerLabel: 'Home' }} />
<Drawer.Screen name="settings" options={{ drawerLabel: 'Settings' }} />
</Drawer>
)
}

render is platform-keyed ({ web?, ios?, android? }). The current platform’s component is picked at render time; if none matches, the default drawer content is used. The render component receives DrawerContentComponentProps from @react-navigation/drawer: state, navigation, descriptors.

Global setup via the setup file

// app/setup.ts
import { setupRendering } from 'one'
import { MyDrawerContent } from './ui/MyDrawerContent'
setupRendering({
Drawer: { web: MyDrawerContent },
})

The global is overridden by <Drawer render={...}> or by passing drawerContent={...} directly.

Dependencies

The Drawer requires these optional peer dependencies to be installed:

npm install @react-navigation/drawer react-native-gesture-handler react-native-reanimated

These 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.