diff --git a/skills/react-navigation/SKILL.md b/skills/react-navigation/SKILL.md new file mode 100644 index 0000000..036ce68 --- /dev/null +++ b/skills/react-navigation/SKILL.md @@ -0,0 +1,66 @@ +--- +name: react-navigation +description: Provides React Navigation UI patterns for stacks, tabs, drawers etc. Use when building navigation UIs with React Navigation, configuring headers, bottom sheets or handling safe areas and insets. +license: MIT +metadata: + author: Callstack + tags: react-navigation, navigation, ui, native-stack, header, bottom-tabs, native-bottom-tabs, material-top-tabs, drawer, form-sheet, status-bar, safe-area, nested-navigators +--- + +# React Navigation + +## Overview + +Guide for building navigation UIs with React Navigation. + +This skill only applies to React Navigation 7. The API and patterns may not work with different versions. + +## API Selection + +React Navigation offers two API - object-based `Static API` and component-based `Dynamic API`. + +- **Existing Apps**: Check the current navigation setup and follow the same API style when using the references +- **New Apps**: If the app does not have an existing navigation setup yet, prefer `Static API` + +## When to Apply + +Reference this skill when: + +- Building navigation UI patterns such as stacks, tabs, drawers, sheets etc. +- Configuring headers and other built-in navigator UI +- Handling safe areas and insets in navigation UI + +## References + +| File | Description | +| ------------------------------------------- | ------------------------------ | +| [stacks.md][stacks] | Stack based navigation | +| [form-sheet.md][form-sheet] | Bottom sheet and form sheets | +| [bottom-tabs.md][bottom-tabs] | Cross-platform bottom tabs | +| [native-bottom-tabs.md][native-bottom-tabs] | Native bottom tabs | +| [material-top-tabs.md][material-top-tabs] | Swipeable Top tabs | +| [drawers.md][drawers] | Drawer navigation and sidebars | +| [header.md][header] | Configuring headers | +| [safe-areas.md][safe-areas] | Safe-area handling | + +## Problem -> Skill Mapping + +| Problem | Start With | +| ------------------------------------------------------------------------- | ------------------------------------------- | +| Showing screens and modals in a stack | [stacks.md][stacks] | +| Showing bottom sheets or form sheets | [form-sheet.md][form-sheet] | +| Showing screens in bottom tabs or responsive sidebars with web support | [bottom-tabs.md][bottom-tabs] | +| Showing screens in native tabs on iOS & Android | [native-bottom-tabs.md][native-bottom-tabs] | +| Showing content in swipeable top tabs | [material-top-tabs.md][material-top-tabs] | +| Using a drawer or sidebar | [drawers.md][drawers] | +| Configuring the header in bottom tab or drawer navigator | [header.md][header] | +| Handling safe-area such as status bar, header insets, tab bar insets etc. | [safe-areas.md][safe-areas] | + +[stacks]: references/stacks.md +[form-sheet]: references/form-sheet.md +[safe-areas]: references/safe-areas.md +[bottom-tabs]: references/bottom-tabs.md +[native-bottom-tabs]: references/native-bottom-tabs.md +[material-top-tabs]: references/material-top-tabs.md +[drawers]: references/drawers.md +[header]: references/header.md diff --git a/skills/react-navigation/references/bottom-tabs.md b/skills/react-navigation/references/bottom-tabs.md new file mode 100644 index 0000000..5a9449c --- /dev/null +++ b/skills/react-navigation/references/bottom-tabs.md @@ -0,0 +1,496 @@ +--- +title: Bottom Tabs +impact: HIGH +tags: react-navigation, bottom-tabs, tab-bar, icons, blur, sidebar, header +--- + +# Skill: Bottom Tabs + +## Description + +Use `createBottomTabNavigator` for cross-platform tab navigation with a tab bar that can stay at the bottom on smaller screens and move to the side on larger layouts if the app needs web support. + +Conditionally use [native-bottom-tabs.md](./native-bottom-tabs.md) on Android and iOS for a native tab bar. + +## When to Use + +- Building primary app destinations behind a tab bar +- The app needs to run on web and mobile + +## Basic Example + +**Static API** + +```tsx +import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'; + +const AppTabs = createBottomTabNavigator({ + screens: { + Home: HomeScreen, + Profile: ProfileScreen, + }, +}); +``` + +**Dynamic API** + +```tsx +import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'; + +const Tab = createBottomTabNavigator(); + +function AppTabs() { + return ( + + + + + ); +} +``` + +## Common Features + +### Displaying Icons + +Use `tabBarIcon` in `screenOptions` or per-screen `options`. Optionally use `tabBarActiveTintColor` and `tabBarInactiveTintColor` to change the color passed to the icon. + +**Static API** + +```tsx +import Ionicons from '@expo/vector-icons/Ionicons'; +import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'; + +const AppTabs = createBottomTabNavigator({ + screenOptions: ({ route }) => ({ + tabBarIcon: ({ focused, color, size }) => { + let iconName; + + switch (route.name) { + case 'Home': + iconName = focused ? 'home' : 'home-outline'; + break; + default: + iconName = focused ? 'settings' : 'settings-outline'; + break; + } + + return ; + }, + tabBarActiveTintColor: 'tomato', + tabBarInactiveTintColor: 'gray', + }), + screens: { + Home: HomeScreen, + Settings: SettingsScreen, + }, +}); +``` + +**Dynamic API** + +```tsx +import Ionicons from '@expo/vector-icons/Ionicons'; +import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'; + +const Tab = createBottomTabNavigator(); + +function AppTabs() { + return ( + ({ + tabBarIcon: ({ focused, color, size }) => { + let iconName; + + switch (route.name) { + case 'Home': + iconName = focused ? 'home' : 'home-outline'; + break; + default: + iconName = focused ? 'settings' : 'settings-outline'; + break; + } + + return ; + }, + tabBarActiveTintColor: 'tomato', + tabBarInactiveTintColor: 'gray', + })} + > + + + + ); +} +``` + +The `tabBarIcon` option can render any React element. Choose between the icon libraries that best fit the app's design and environment: + +- `@expo/vector-icons` if Expo SDK is configured in the app +- `react-native-vector-icons` for an app using React Native Community CLI +- `` for local images + +### Scroll to Top on Tab Press + +Use `useScrollToTop` on a scrollable ref inside a screen in the tab navigator to automatically scroll to the top when the tab is pressed while already focused. + +```tsx +import * as React from 'react'; +import { ScrollView } from 'react-native'; +import { useScrollToTop } from '@react-navigation/native'; + +function FeedScreen() { + const ref = React.useRef(null); + + useScrollToTop(ref); + + return {/* content */}; +} +``` + +### Custom Background Such as Blur + +Use `tabBarBackground` for custom chrome such as blur effects, image, or gradient backgrounds. When the background should show through the tab bar, set `tabBarStyle: { position: 'absolute' }` and use `useBottomTabBarHeight` inside the screens to pad the content. + +**Static API** + +```tsx +import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'; +import { BlurView } from 'expo-blur'; +import { StyleSheet } from 'react-native'; + +const AppTabs = createBottomTabNavigator({ + screenOptions: { + tabBarStyle: { position: 'absolute' }, + tabBarBackground: () => ( + + ), + }, + screens: { + Home: HomeScreen, + Profile: ProfileScreen, + }, +}); +``` + +**Dynamic API** + +```tsx +import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'; +import { BlurView } from 'expo-blur'; +import { StyleSheet } from 'react-native'; + +const Tab = createBottomTabNavigator(); + +function AppTabs() { + return ( + ( + + ), + }} + > + + + + ); +} +``` + +### Custom Tab Bar + +Use the `tabBar` option if a custom design is needed. Use the `state` prop to access the list of screens and `descriptors` to access the options for each screen. Use the `navigation` prop passed to the tab bar for navigation instead of `useNavigation`. + +```tsx +import { Text, View } from 'react-native'; +import { useLinkBuilder } from '@react-navigation/native'; +import { PlatformPressable } from '@react-navigation/elements'; + +function MyTabBar({ state, descriptors, navigation }) { + const { buildHref } = useLinkBuilder(); + + return ( + + {state.routes.map((route, index) => { + const { options } = descriptors[route.key]; + const label = + options.tabBarLabel !== undefined + ? options.tabBarLabel + : options.title !== undefined + ? options.title + : route.name; + + const isFocused = state.index === index; + + return ( + { + const event = navigation.emit({ + type: 'tabPress', + target: route.key, + canPreventDefault: true, + }); + + if (!isFocused && !event.defaultPrevented) { + navigation.navigate(route.name, route.params); + } + }} + onLongPress={() => + navigation.emit({ + type: 'tabLongPress', + target: route.key, + }) + } + style={{ flex: 1, alignItems: 'center', paddingVertical: 12 }} + > + {label} + + ); + })} + + ); +} +``` + +**Static API** + +```tsx +import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'; + +const AppTabs = createBottomTabNavigator({ + tabBar: (props) => , + screens: { + Home: HomeScreen, + Profile: ProfileScreen, + }, +}); +``` + +**Dynamic API** + +```tsx +import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'; + +const Tab = createBottomTabNavigator(); + +function AppTabs() { + return ( + }> + + + + ); +} +``` + +### Sidebar + +Set `tabBarPosition` to `left` or `right` to render the tab bar as a sidebar. Choose the position based on the screen width for responsive layouts. + +**Static API** + +```tsx +import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'; + +const AppTabs = createBottomTabNavigator({ + screenOptions: { + tabBarPosition: 'left', + }, + screens: { + Home: HomeScreen, + Profile: ProfileScreen, + }, +}).with(({ Navigator }) => { + const dimensions = useWindowDimensions(); + + return ( + = 768 ? 'left' : 'bottom', + }} + /> + ); +}); +``` + +**Dynamic API** + +```tsx +import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'; +import { useWindowDimensions } from 'react-native'; + +const Tab = createBottomTabNavigator(); + +function AppTabs() { + const dimensions = useWindowDimensions(); + + return ( + = 768 ? 'left' : 'bottom', + }} + > + + + + ); +} +``` + +For a compact sidebar, use `tabBarVariant: 'material'` together with `tabBarLabelPosition: 'below-icon'`. + +### Customizing Header + +Bottom tabs show a header by default. Use [header.md](./header.md) for common customization patterns. + +A custom header can be shown with the `header` option if a custom design is needed. + +**Static API** + +```tsx +import { getHeaderTitle } from '@react-navigation/elements'; +import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'; + +const AppTabs = createBottomTabNavigator({ + screens: { + Home: { + screen: HomeScreen, + options: { + headerStyle: { + height: 80, + }, + header: ({ route, options }) => { + const title = getHeaderTitle(options, route.name); + + return ; + }, + }, + }, + }, +}); +``` + +**Dynamic API** + +```tsx +import { getHeaderTitle } from '@react-navigation/elements'; +import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'; + +const Tab = createBottomTabNavigator(); + +function AppTabs() { + return ( + + { + const title = getHeaderTitle(options, route.name); + + return ; + }, + }} + /> + + ); +} +``` + +- Set `headerShown: false` to hide the header. +- If a custom header uses a non-default height, set `headerStyle: { height: ... }` explicitly to avoid measurement glitches. + +## Hiding Tab Bar on Certain Screens + +The tab bar is shown on all screens in the tab navigator. To hide the tab bar on certain screens, put those screens in a parent stack navigator instead. + +**Static API** + +```tsx +import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'; +import { createNativeStackNavigator } from '@react-navigation/native-stack'; + +const HomeTabs = createBottomTabNavigator({ + screens: { + Home: HomeScreen, + Feed: FeedScreen, + Notifications: NotificationsScreen, + }, +}); + +const AppStack = createNativeStackNavigator({ + screens: { + Main: { + screen: HomeTabs, + options: { + headerShown: false, + }, + }, + Profile: ProfileScreen, + Settings: SettingsScreen, + }, +}); +``` + +**Dynamic API** + +```tsx +import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'; +import { createNativeStackNavigator } from '@react-navigation/native-stack'; + +const Stack = createNativeStackNavigator(); +const Tab = createBottomTabNavigator(); + +function HomeTabs() { + return ( + + + + + + ); +} + +function AppStack() { + return ( + + + + + + ); +} +``` + +- Prefer this structure over trying to hide the parent tab bar from screens inside the tab navigator as it can lead to layout glitches. +- Use [stacks.md](./stacks.md) for stack-specific options on the full-screen routes. + +## Canonical Docs + +- [Bottom Tabs Navigator](https://reactnavigation.org/docs/bottom-tab-navigator) +- [Customizing bottom tab bar](https://reactnavigation.org/docs/customizing-tabbar) +- [Hiding tab bar in specific screens](https://reactnavigation.org/docs/hiding-tabbar-in-screens) + +## Related Skills + +- [header.md](./header.md) +- [native-bottom-tabs.md](./native-bottom-tabs.md) +- [material-top-tabs.md](./material-top-tabs.md) +- [safe-areas.md](./safe-areas.md) diff --git a/skills/react-navigation/references/drawers.md b/skills/react-navigation/references/drawers.md new file mode 100644 index 0000000..c178f43 --- /dev/null +++ b/skills/react-navigation/references/drawers.md @@ -0,0 +1,474 @@ +--- +title: Drawer Navigator +impact: HIGH +tags: react-navigation, drawer, sidebar, master-detail, header, responsive-layout +--- + +# Skill: Drawer Navigator + +## Description + +Use `createDrawerNavigator` for a navigation drawer or sidebar that switches between app sections. If using a drawer for displaying content instead of navigation, use [`react-native-drawer-layout`](https://reactnavigation.org/docs/drawer-layout/) instead. + +## When to Use + +- Building app sections behind a drawer or sidebar +- Showing a permanent sidebar on larger screens and a drawer on smaller screens +- Using the drawer as the master pane in a master-detail layout + +## Prerequisites + +Install and configure `react-native-gesture-handler`, `react-native-reanimated`, and `react-native-worklets` for drawer navigator to work on native platforms. + +## Basic Example + +**Static API** + +```tsx +import { createDrawerNavigator } from '@react-navigation/drawer'; + +const AppDrawer = createDrawerNavigator({ + screens: { + Home: HomeScreen, + Profile: ProfileScreen, + }, +}); +``` + +**Dynamic API** + +```tsx +import { createDrawerNavigator } from '@react-navigation/drawer'; + +const Drawer = createDrawerNavigator(); + +function AppDrawer() { + return ( + + + + + ); +} +``` + +## Opening and Closing the Drawer + +Use `navigation.openDrawer()`, `navigation.closeDrawer()`, and `navigation.toggleDrawer()` inside drawer screens to open or close the drawer programmatically. + +```tsx +import { Button, View } from 'react-native'; +import { useNavigation } from '@react-navigation/native'; + +function HomeScreen() { + const navigation = useNavigation(); + + return ( + +