|
2 | 2 | title: Using BottomNavigation with React Navigation |
3 | 3 | --- |
4 | 4 |
|
5 | | -:::caution |
6 | | -The `createMaterialBottomTabNavigator` has been deprecated as of `react-native-paper@5.14.0`. Instead, use `@react-navigation/bottom-tabs` version `7.x` or later, combined with `BottomNavigation.Bar` to achieve a Material Design look. |
| 5 | +Build a Material Design bottom tab bar by combining two pieces: |
7 | 6 |
|
8 | | -For implementation details, see the [dedicated example](https://callstack.github.io/react-native-paper/docs/components/BottomNavigation/BottomNavigationBar#with-react-navigation). |
9 | | -::: |
10 | | - |
11 | | -A material-design themed tab bar on the bottom of the screen that lets you switch between different routes with animation. Routes are lazily initialized - their screen components are not mounted until they are first focused. |
12 | | - |
13 | | -This wraps the [`BottomNavigation`](https://callstack.github.io/react-native-paper/docs/components/BottomNavigation/) component from `react-native-paper`, however if you [configure the Babel plugin](https://callstack.github.io/react-native-paper/docs/guides/getting-started/), it won't include the whole library in your bundle. |
| 7 | +- `@react-navigation/bottom-tabs` handles routing, state, and screen options. |
| 8 | +- `BottomNavigation.Bar` renders the Material 3 tab bar (ripple, badges, shifting/labeled modes). |
14 | 9 |
|
15 | 10 | <img src="/react-native-paper/screenshots/material-bottom-tabs.gif" style={{ width: '420px', maxWidth: '100%', margin: '16px 0' }} /> |
16 | 11 |
|
17 | 12 | :::info |
18 | | -To use this navigator, ensure that you have [`@react-navigation/native` and its dependencies (follow this guide)](https://reactnavigation.org/docs/getting-started): |
| 13 | +Install [`@react-navigation/native`](https://reactnavigation.org/docs/getting-started) and [`@react-navigation/bottom-tabs`](https://reactnavigation.org/docs/bottom-tab-navigator) first. |
19 | 14 | ::: |
20 | 15 |
|
21 | | -> 👉 For a complete example please visit `createMaterialBottomTabNavigator` [snack](https://snack.expo.dev/@react-native-paper/creatematerialbottomtabnavigator) |
| 16 | +## Quick example |
22 | 17 |
|
23 | | -## API Definition |
| 18 | +Pass a `BottomNavigation.Bar` to the navigator's `tabBar` prop. The bar reads navigation state and dispatches `tabPress` events back: |
24 | 19 |
|
25 | | -To use this tab navigator, import it from `react-native-paper/react-navigation`: |
| 20 | +```jsx |
| 21 | +import MaterialCommunityIcons from '@react-native-vector-icons/material-design-icons'; |
| 22 | +import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'; |
| 23 | +import { CommonActions } from '@react-navigation/native'; |
| 24 | +import { BottomNavigation } from 'react-native-paper'; |
| 25 | +import { useSafeAreaInsets } from 'react-native-safe-area-context'; |
26 | 26 |
|
27 | | -```js |
28 | | -import { createMaterialBottomTabNavigator } from 'react-native-paper/react-navigation'; |
29 | | - |
30 | | -const Tab = createMaterialBottomTabNavigator(); |
| 27 | +const Tab = createBottomTabNavigator(); |
31 | 28 |
|
32 | 29 | function MyTabs() { |
33 | | - return ( |
34 | | - <Tab.Navigator> |
35 | | - <Tab.Screen name="Home" component={HomeScreen} /> |
36 | | - <Tab.Screen name="Settings" component={SettingsScreen} /> |
37 | | - </Tab.Navigator> |
38 | | - ); |
39 | | -} |
40 | | -``` |
41 | | - |
42 | | -> 👉 For a complete usage guide please visit [Tab Navigation](https://reactnavigation.org/docs/tab-based-navigation/) |
43 | | -
|
44 | | -### Props |
45 | | - |
46 | | -The `Tab.Navigator` component accepts following props: |
47 | | - |
48 | | -#### `id` |
49 | | - |
50 | | -Optional unique ID for the navigator. This can be used with [`navigation.getParent`](https://reactnavigation.org/docs/navigation-prop#getparent) to refer to this navigator in a child navigator. |
51 | | - |
52 | | -#### `initialRouteName` |
53 | | - |
54 | | -The name of the route to render on first load of the navigator. |
55 | | - |
56 | | -#### `screenOptions` |
57 | | - |
58 | | -Default options to use for the screens in the navigator. |
59 | | - |
60 | | -#### `backBehavior` |
61 | | - |
62 | | -This controls what happens when `goBack` is called in the navigator. This includes pressing the device's back button or back gesture on Android. |
63 | | - |
64 | | -It supports the following values: |
65 | | - |
66 | | -- `firstRoute` - return to the first screen defined in the navigator (default) |
67 | | -- `initialRoute` - return to initial screen passed in `initialRouteName` prop, if not passed, defaults to the first screen |
68 | | -- `order` - return to screen defined before the focused screen |
69 | | -- `history` - return to last visited screen in the navigator; if the same screen is visited multiple times, the older entries are dropped from the history |
70 | | -- `none` - do not handle back button |
71 | | - |
72 | | -#### `shifting` |
73 | | - |
74 | | -Whether the shifting style is used, the active tab icon shifts up to show the label and the inactive tabs won't have a label. |
75 | | - |
76 | | -By default, this is `true` when you have more than 3 tabs. Pass `shifting={false}` to explicitly disable this animation, or `shifting={true}` to always use this animation. |
77 | | - |
78 | | -#### `labeled` |
79 | | - |
80 | | -Whether to show labels in tabs. When `false`, only icons will be displayed. |
81 | | - |
82 | | -#### `activeColor` |
83 | | - |
84 | | -Custom color for icon and label in the active tab. |
85 | | - |
86 | | -#### `inactiveColor` |
87 | | - |
88 | | -Custom color for icon and label in the inactive tab. |
89 | | - |
90 | | -#### `barStyle` |
91 | | - |
92 | | -Style for the bottom navigation bar. You can pass custom background color here: |
93 | | - |
94 | | -```js |
95 | | -<Tab.Navigator |
96 | | - initialRouteName="Home" |
97 | | - activeColor="#f0edf6" |
98 | | - inactiveColor="#3e2465" |
99 | | - barStyle={{ backgroundColor: '#694fad' }} |
100 | | -> |
101 | | - {/* ... */} |
102 | | -</Tab.Navigator> |
103 | | -``` |
104 | | - |
105 | | -If you have a translucent navigation bar on Android, you can also set a bottom padding here: |
106 | | - |
107 | | -```js |
108 | | -<Tab.Navigator |
109 | | - initialRouteName="Home" |
110 | | - activeColor="#f0edf6" |
111 | | - inactiveColor="#3e2465" |
112 | | - barStyle={{ paddingBottom: 48 }} |
113 | | -> |
114 | | - {/* ... */} |
115 | | -</Tab.Navigator> |
116 | | -``` |
117 | | - |
118 | | -#### `theme` |
119 | | - |
120 | | -Enables the customization of default theme attributes (e.g. colors) or facilitates the utilization of a personalized custom theme. |
121 | | - |
122 | | -### Options |
123 | | - |
124 | | -The following [options](https://reactnavigation.org/docs/screen-options) can be used to configure the screens in the navigator: |
| 30 | + const insets = useSafeAreaInsets(); |
125 | 31 |
|
126 | | -#### `title` |
127 | | - |
128 | | -Generic title that can be used as a fallback for `headerTitle` and `tabBarLabel`. |
129 | | - |
130 | | -#### `tabBarIcon` |
131 | | - |
132 | | -Function that given `{ focused: boolean, color: string }` returns a React.Node, to display in the tab bar. |
133 | | - |
134 | | -#### `tabBarColor` <div class="badge badge-deprecated">In v5.x works only with theme version 2.</div> |
135 | | - |
136 | | -Color for the tab bar when the tab corresponding to the screen is active. Used for the ripple effect. This is only supported when `shifting` is `true`. |
137 | | - |
138 | | -#### `tabBarLabel` |
139 | | - |
140 | | -Title string of a tab displayed in the tab bar. When undefined, scene `title` is used. To hide, see `labeled` option in the previous section. |
141 | | - |
142 | | -#### `tabBarBadge` |
143 | | - |
144 | | -Badge to show on the tab icon, can be `true` to show a dot, `string` or `number` to show text. |
145 | | - |
146 | | -#### `tabBarAccessibilityLabel` |
147 | | - |
148 | | -Accessibility label for the tab button. This is read by the screen reader when the user taps the tab. It's recommended to set this if you don't have a label for the tab. |
149 | | - |
150 | | -#### `tabBarTestID` |
151 | | - |
152 | | -ID to locate this tab button in tests. |
153 | | - |
154 | | -### Events |
155 | | - |
156 | | -The navigator can [emit events](https://reactnavigation.org/docs/navigation-events) on certain actions. Supported events are: |
157 | | - |
158 | | -#### `tabPress` |
159 | | - |
160 | | -This event is fired when the user presses the tab button for the current screen in the tab bar. By default a tab press does several things: |
161 | | - |
162 | | -- If the tab is not focused, tab press will focus that tab |
163 | | -- If the tab is already focused: |
164 | | - - If the screen for the tab renders a scroll view, you can use [`useScrollToTop`](https://reactnavigation.org/docs/use-scroll-to-top) to scroll it to top |
165 | | - - If the screen for the tab renders a stack navigator, a `popToTop` action is performed on the stack |
166 | | - |
167 | | -To prevent the default behavior, you can call `event.preventDefault`: |
168 | | - |
169 | | -```js |
170 | | -React.useEffect(() => { |
171 | | - const unsubscribe = navigation.addListener('tabPress', (e) => { |
172 | | - // Prevent default behavior |
173 | | - |
174 | | - e.preventDefault(); |
175 | | - // Do something manually |
176 | | - // ... |
177 | | - }); |
178 | | - |
179 | | - return unsubscribe; |
180 | | -}, [navigation]); |
181 | | -``` |
182 | | - |
183 | | -### Helpers |
184 | | - |
185 | | -The tab navigator adds the following methods to the navigation prop: |
186 | | - |
187 | | -#### `jumpTo` |
188 | | - |
189 | | -Navigates to an existing screen in the tab navigator. The method accepts following arguments: |
190 | | - |
191 | | -- `name` - _string_ - Name of the route to jump to. |
192 | | -- `params` - _object_ - Screen params to pass to the destination route. |
193 | | - |
194 | | -<samp id="material-tab-jump-to" /> |
195 | | - |
196 | | -```js |
197 | | -navigation.jumpTo('Profile', { name: 'Michaś' }); |
198 | | -``` |
199 | | - |
200 | | -## Example |
201 | | - |
202 | | -```js |
203 | | -import { createMaterialBottomTabNavigator } from 'react-native-paper/react-navigation'; |
204 | | -import MaterialDesignIcons from '@react-native-vector-icons/material-design-icons'; |
205 | | - |
206 | | -const Tab = createMaterialBottomTabNavigator(); |
207 | | - |
208 | | -function MyTabs() { |
209 | 32 | return ( |
210 | 33 | <Tab.Navigator |
211 | | - initialRouteName="Feed" |
212 | | - activeColor="#e91e63" |
213 | | - barStyle={{ backgroundColor: 'tomato' }} |
| 34 | + screenOptions={{ animation: 'shift' }} |
| 35 | + tabBar={({ navigation, state, descriptors }) => ( |
| 36 | + <BottomNavigation.Bar |
| 37 | + navigationState={state} |
| 38 | + safeAreaInsets={insets} |
| 39 | + onTabPress={({ route, preventDefault }) => { |
| 40 | + const event = navigation.emit({ |
| 41 | + type: 'tabPress', |
| 42 | + target: route.key, |
| 43 | + canPreventDefault: true, |
| 44 | + }); |
| 45 | + if (event.defaultPrevented) { |
| 46 | + preventDefault(); |
| 47 | + } else { |
| 48 | + navigation.dispatch({ |
| 49 | + ...CommonActions.navigate(route.name, route.params), |
| 50 | + target: state.key, |
| 51 | + }); |
| 52 | + } |
| 53 | + }} |
| 54 | + renderIcon={({ route, focused, color }) => |
| 55 | + descriptors[route.key].options.tabBarIcon?.({ |
| 56 | + focused, |
| 57 | + color, |
| 58 | + size: 24, |
| 59 | + }) ?? null |
| 60 | + } |
| 61 | + getLabelText={({ route }) => { |
| 62 | + const { options } = descriptors[route.key]; |
| 63 | + return typeof options.tabBarLabel === 'string' |
| 64 | + ? options.tabBarLabel |
| 65 | + : typeof options.title === 'string' |
| 66 | + ? options.title |
| 67 | + : route.name; |
| 68 | + }} |
| 69 | + /> |
| 70 | + )} |
214 | 71 | > |
215 | 72 | <Tab.Screen |
216 | | - name="Feed" |
217 | | - component={Feed} |
218 | | - options={{ |
219 | | - tabBarLabel: 'Home', |
220 | | - tabBarIcon: ({ color }) => ( |
221 | | - <MaterialDesignIcons name="home" color={color} size={26} /> |
222 | | - ), |
223 | | - }} |
224 | | - /> |
225 | | - <Tab.Screen |
226 | | - name="Notifications" |
227 | | - component={Notifications} |
| 73 | + name="Home" |
| 74 | + component={HomeScreen} |
228 | 75 | options={{ |
229 | | - tabBarLabel: 'Updates', |
230 | 76 | tabBarIcon: ({ color }) => ( |
231 | | - <MaterialDesignIcons name="bell" color={color} size={26} /> |
| 77 | + <MaterialCommunityIcons name="home" color={color} size={26} /> |
232 | 78 | ), |
233 | 79 | }} |
234 | 80 | /> |
235 | 81 | <Tab.Screen |
236 | | - name="Profile" |
237 | | - component={Profile} |
| 82 | + name="Settings" |
| 83 | + component={SettingsScreen} |
238 | 84 | options={{ |
239 | | - tabBarLabel: 'Profile', |
240 | 85 | tabBarIcon: ({ color }) => ( |
241 | | - <MaterialDesignIcons name="account" color={color} size={26} /> |
| 86 | + <MaterialCommunityIcons name="cog" color={color} size={26} /> |
242 | 87 | ), |
243 | 88 | }} |
244 | 89 | /> |
|
0 commit comments