Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
283 changes: 73 additions & 210 deletions docs/docs/guides/09-bottom-navigation.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,246 +3,109 @@ title: Using BottomNavigation with React Navigation
---

:::caution
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.

For implementation details, see the [dedicated example](https://callstack.github.io/react-native-paper/docs/components/BottomNavigation/BottomNavigationBar#with-react-navigation).
`createMaterialBottomTabNavigator` was deprecated in `react-native-paper@5.14.0` and removed in `react-native-paper@6.0.0`. Use [`@react-navigation/bottom-tabs`](https://reactnavigation.org/docs/bottom-tab-navigator) (v7+) with [`BottomNavigation.Bar`](https://callstack.github.io/react-native-paper/docs/components/BottomNavigation/BottomNavigationBar) instead.
:::

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.
Build a Material Design bottom tab bar by combining two pieces:

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.
- `@react-navigation/bottom-tabs` handles routing, state, and screen options.
- `BottomNavigation.Bar` renders the Material 3 tab bar (ripple, badges, shifting/labeled modes).

<img src="/react-native-paper/screenshots/material-bottom-tabs.gif" style={{ width: '420px', maxWidth: '100%', margin: '16px 0' }} />

:::info
To use this navigator, ensure that you have [`@react-navigation/native` and its dependencies (follow this guide)](https://reactnavigation.org/docs/getting-started):
Install [`@react-navigation/native`](https://reactnavigation.org/docs/getting-started) and [`@react-navigation/bottom-tabs@^7`](https://reactnavigation.org/docs/bottom-tab-navigator) first.
:::

> 👉 For a complete example please visit `createMaterialBottomTabNavigator` [snack](https://snack.expo.dev/@react-native-paper/creatematerialbottomtabnavigator)

## API Definition
## Quick example

To use this tab navigator, import it from `react-native-paper/react-navigation`:
Pass a `BottomNavigation.Bar` to the navigator's `tabBar` prop. The bar reads navigation state and dispatches `tabPress` events back:

```js
import { createMaterialBottomTabNavigator } from 'react-native-paper/react-navigation';
```jsx
import { CommonActions } from '@react-navigation/native';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import { BottomNavigation } from 'react-native-paper';
import MaterialCommunityIcons from '@expo/vector-icons/MaterialCommunityIcons';

const Tab = createMaterialBottomTabNavigator();

function MyTabs() {
return (
<Tab.Navigator>
<Tab.Screen name="Home" component={HomeScreen} />
<Tab.Screen name="Settings" component={SettingsScreen} />
</Tab.Navigator>
);
}
```

> 👉 For a complete usage guide please visit [Tab Navigation](https://reactnavigation.org/docs/tab-based-navigation/)

### Props

The `Tab.Navigator` component accepts following props:

#### `id`

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.

#### `initialRouteName`

The name of the route to render on first load of the navigator.

#### `screenOptions`

Default options to use for the screens in the navigator.

#### `backBehavior`

This controls what happens when `goBack` is called in the navigator. This includes pressing the device's back button or back gesture on Android.

It supports the following values:

- `firstRoute` - return to the first screen defined in the navigator (default)
- `initialRoute` - return to initial screen passed in `initialRouteName` prop, if not passed, defaults to the first screen
- `order` - return to screen defined before the focused screen
- `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
- `none` - do not handle back button

#### `shifting`

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.

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.

#### `labeled`

Whether to show labels in tabs. When `false`, only icons will be displayed.

#### `activeColor`

Custom color for icon and label in the active tab.

#### `inactiveColor`

Custom color for icon and label in the inactive tab.

#### `barStyle`

Style for the bottom navigation bar. You can pass custom background color here:

```js
<Tab.Navigator
initialRouteName="Home"
activeColor="#f0edf6"
inactiveColor="#3e2465"
barStyle={{ backgroundColor: '#694fad' }}
>
{/* ... */}
</Tab.Navigator>
```

If you have a translucent navigation bar on Android, you can also set a bottom padding here:

```js
<Tab.Navigator
initialRouteName="Home"
activeColor="#f0edf6"
inactiveColor="#3e2465"
barStyle={{ paddingBottom: 48 }}
>
{/* ... */}
</Tab.Navigator>
```

#### `theme`

Enables the customization of default theme attributes (e.g. colors) or facilitates the utilization of a personalized custom theme.

### Options

The following [options](https://reactnavigation.org/docs/screen-options) can be used to configure the screens in the navigator:

#### `title`

Generic title that can be used as a fallback for `headerTitle` and `tabBarLabel`.

#### `tabBarIcon`

Function that given `{ focused: boolean, color: string }` returns a React.Node, to display in the tab bar.

#### `tabBarColor` <div class="badge badge-deprecated">In v5.x works only with theme version 2.</div>

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

#### `tabBarLabel`

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.

#### `tabBarBadge`

Badge to show on the tab icon, can be `true` to show a dot, `string` or `number` to show text.

#### `tabBarAccessibilityLabel`

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.

#### `tabBarTestID`

ID to locate this tab button in tests.

### Events

The navigator can [emit events](https://reactnavigation.org/docs/navigation-events) on certain actions. Supported events are:

#### `tabPress`

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:

- If the tab is not focused, tab press will focus that tab
- If the tab is already focused:
- 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
- If the screen for the tab renders a stack navigator, a `popToTop` action is performed on the stack

To prevent the default behavior, you can call `event.preventDefault`:

```js
React.useEffect(() => {
const unsubscribe = navigation.addListener('tabPress', (e) => {
// Prevent default behavior

e.preventDefault();
// Do something manually
// ...
});

return unsubscribe;
}, [navigation]);
```

### Helpers

The tab navigator adds the following methods to the navigation prop:

#### `jumpTo`

Navigates to an existing screen in the tab navigator. The method accepts following arguments:

- `name` - _string_ - Name of the route to jump to.
- `params` - _object_ - Screen params to pass to the destination route.

<samp id="material-tab-jump-to" />

```js
navigation.jumpTo('Profile', { name: 'Michaś' });
```

## Example

```js
import { createMaterialBottomTabNavigator } from 'react-native-paper/react-navigation';
import MaterialDesignIcons from '@react-native-vector-icons/material-design-icons';

const Tab = createMaterialBottomTabNavigator();
const Tab = createBottomTabNavigator();

function MyTabs() {
return (
<Tab.Navigator
initialRouteName="Feed"
activeColor="#e91e63"
barStyle={{ backgroundColor: 'tomato' }}
screenOptions={{ animation: 'shift' }}
tabBar={({ navigation, state, descriptors, insets }) => (
<BottomNavigation.Bar
navigationState={state}
safeAreaInsets={insets}
onTabPress={({ route, preventDefault }) => {
const event = navigation.emit({
type: 'tabPress',
target: route.key,
canPreventDefault: true,
});
if (event.defaultPrevented) {
preventDefault();
} else {
navigation.dispatch({
...CommonActions.navigate(route.name, route.params),
target: state.key,
});
}
}}
renderIcon={({ route, focused, color }) =>
descriptors[route.key].options.tabBarIcon?.({
focused,
color,
size: 24,
}) ?? null
}
getLabelText={({ route }) => {
const { options } = descriptors[route.key];
return typeof options.tabBarLabel === 'string'
? options.tabBarLabel
: typeof options.title === 'string'
? options.title
: route.name;
}}
/>
)}
>
<Tab.Screen
name="Feed"
component={Feed}
name="Home"
component={HomeScreen}
options={{
tabBarLabel: 'Home',
tabBarIcon: ({ color }) => (
<MaterialDesignIcons name="home" color={color} size={26} />
<MaterialCommunityIcons name="home" color={color} size={26} />
),
}}
/>
<Tab.Screen
name="Notifications"
component={Notifications}
name="Settings"
component={SettingsScreen}
options={{
tabBarLabel: 'Updates',
tabBarIcon: ({ color }) => (
<MaterialDesignIcons name="bell" color={color} size={26} />
),
}}
/>
<Tab.Screen
name="Profile"
component={Profile}
options={{
tabBarLabel: 'Profile',
tabBarIcon: ({ color }) => (
<MaterialDesignIcons name="account" color={color} size={26} />
<MaterialCommunityIcons name="cog" color={color} size={26} />
),
}}
/>
</Tab.Navigator>
);
}
```

## References

- [`BottomNavigation.Bar` props](https://callstack.github.io/react-native-paper/docs/components/BottomNavigation/BottomNavigationBar): `activeColor`, `inactiveColor`, `shifting`, `labeled`, `barStyle`, `theme`, badges.
- [`BottomNavigation.Bar` example](https://callstack.github.io/react-native-paper/docs/components/BottomNavigation/BottomNavigationBar#with-react-navigation): static-config and dynamic-tree variants.
- [React Navigation bottom-tabs](https://reactnavigation.org/docs/bottom-tab-navigator): navigator props, screen options (`tabBarIcon`, `tabBarLabel`, `tabBarBadge`), `tabPress` events, `jumpTo` helper.

## Migration

| Old (removed) | New |
|---|---|
| `createMaterialBottomTabNavigator()` | `createBottomTabNavigator()` from `@react-navigation/bottom-tabs` |
| `<Tab.Navigator activeColor inactiveColor barStyle shifting labeled theme>` | Pass the same props to `<BottomNavigation.Bar>` inside `tabBar` |
| `options.tabBarIcon` / `tabBarLabel` / `tabBarBadge` | Same names; read via `descriptors[route.key].options` in `renderIcon` / `getLabelText` |
| `options.tabBarColor` (theme v2) | Removed. MD3 uses tonal surface colors. |
| `navigation.jumpTo(name, params)` | Same. Provided by `@react-navigation/bottom-tabs`. |
| `tabPress` event | Same. Emitted by `@react-navigation/bottom-tabs`. |
6 changes: 3 additions & 3 deletions docs/src/components/BannerExample.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ import {
Avatar,
Button,
FAB,
MD3DarkTheme as DarkTheme,
MD3LightTheme as DefaultTheme,
DarkTheme,
LightTheme,
ProgressBar,
PaperProvider,
RadioButton,
Expand Down Expand Up @@ -167,7 +167,7 @@ const Shimmer = () => {
const ThemedBannerExample = () => {
const isDarkTheme = useColorMode().colorMode === 'dark';
return (
<PaperProvider theme={isDarkTheme ? DarkTheme : DefaultTheme}>
<PaperProvider theme={isDarkTheme ? DarkTheme : LightTheme}>
<BannerExample />
</PaperProvider>
);
Expand Down
6 changes: 3 additions & 3 deletions docs/src/components/GetStartedButtons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ import Link from '@docusaurus/Link';
import { useColorMode } from '@docusaurus/theme-common';
import {
Button,
MD3DarkTheme as DarkTheme,
MD3LightTheme as DefaultTheme,
DarkTheme,
LightTheme,
PaperProvider,
} from 'react-native-paper';

Expand Down Expand Up @@ -95,7 +95,7 @@ const Shimmer = () => {
const ThemedGetStarted = () => {
const isDarkTheme = useColorMode().colorMode === 'dark';
return (
<PaperProvider theme={isDarkTheme ? DarkTheme : DefaultTheme}>
<PaperProvider theme={isDarkTheme ? DarkTheme : LightTheme}>
<GetStartedButton />
</PaperProvider>
);
Expand Down
6 changes: 3 additions & 3 deletions example/src/DrawerItems.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
Button,
Dialog,
Drawer,
MD3Colors,
Palette,
Switch,
Text,
TouchableRipple,
Expand Down Expand Up @@ -136,8 +136,8 @@ function DrawerItems() {

const coloredLabelTheme = {
colors: {
secondaryContainer: MD3Colors.tertiary80,
onSecondaryContainer: MD3Colors.tertiary20,
secondaryContainer: Palette.tertiary80,
onSecondaryContainer: Palette.tertiary20,
},
};

Expand Down
4 changes: 2 additions & 2 deletions example/src/Examples/ActivityIndicatorExample.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as React from 'react';
import { StyleSheet, View } from 'react-native';

import { ActivityIndicator, FAB, List, MD3Colors } from 'react-native-paper';
import { ActivityIndicator, FAB, List, Palette } from 'react-native-paper';

import ScreenWrapper from '../ScreenWrapper';

Expand Down Expand Up @@ -41,7 +41,7 @@ const ActivityIndicatorExample = () => {
<List.Section title="Custom color">
<ActivityIndicator
animating={animating}
color={MD3Colors.error20}
color={Palette.error20}
hidesWhenStopped={false}
/>
</List.Section>
Expand Down
Loading
Loading