# BottomNavigation (React Native)

> Top-level destinations at the bottom of the app, Material 3 style: icon in a pill, labels and badges.

GramproKit for React Native · Mobile · Beta · Source: https://kit.gramproindia.com/native/docs/bottom-navigation

> **Beta:** React Native support is in beta. APIs may change or break between prereleases (npm tag `native`).

_Interactive demo:_ [open the live example](https://kit.gramproindia.com/native/docs/bottom-navigation). The example's source:

```tsx
import { useState } from "react";
import { ScrollView, Text, View } from "react-native";
import { BottomNavigation, type BottomNavigationItem } from "@/component-lib/bottom-navigation";
import { useKitTheme } from "@/component-lib/shared/native";
import { Section } from "./layout"; // Section and Row: page layout for the demo
import { FakeRows, MiniScreen, TextIcon } from "./mobileFrame";

const icon = (glyph: string) => ({ color }: { color: string }) => <TextIcon glyph={glyph} color={color} />;

const ITEMS: BottomNavigationItem[] = [
  { key: "home", label: "Home", icon: icon("⌂") },
  { key: "invoices", label: "Invoices", icon: icon("▤"), badge: 3 },
  { key: "payments", label: "Payments", icon: icon("₹"), badge: 128 },
  { key: "profile", label: "Profile", icon: icon("◉"), badge: true },
];

export function BottomNavigationDemo() {
  const { tokens } = useKitTheme();
  const [tab, setTab] = useState("invoices");
  const [reselects, setReselects] = useState(0);
  return (
    <>
      <Section title="BottomNavigation · badges, reselect">
        <MiniScreen>
          <View style={{ flex: 1 }}>
            <View style={{ padding: 16 }}>
              <Text style={{ color: tokens.fg, fontSize: 20, fontWeight: "700" }}>
                {ITEMS.find((i) => i.key === tab)?.label}
              </Text>
              <Text style={{ color: tokens.muted }}>Tap the active tab again: reselected {reselects}×</Text>
            </View>
            <ScrollView nestedScrollEnabled>
              <FakeRows count={6} />
            </ScrollView>
          </View>
          <BottomNavigation
            safeArea={false}
            items={ITEMS}
            value={tab}
            onValueChange={setTab}
            onReselect={() => setReselects((n) => n + 1)}
          />
        </MiniScreen>
      </Section>

      <Section title="BottomNavigation · label only when active, disabled item">
        <MiniScreen height={64}>
          <BottomNavigation
            safeArea={false}
            labelVisibility="active"
            items={[...ITEMS.slice(0, 3), { key: "admin", label: "Admin", icon: icon("⚙"), disabled: true }]}
          />
        </MiniScreen>
      </Section>
    </>
  );
}
```

## Install

```bash
npx @grampro/kit@native add BottomNavigation
```

## Usage

```tsx
import { BottomNavigation } from "@/component-lib/bottom-navigation";

<BottomNavigation
  value={tab}
  onValueChange={setTab}
  items={[
    { key: "home", label: "Home", icon: ({ color }) => <HomeIcon color={color} /> },
    { key: "invoices", label: "Invoices", badge: 3 },
    { key: "settings", label: "Settings" },
  ]}
/>
```

## Props

### BottomNavigationProps

| Prop | Type | Description |
|---|---|---|
| `items` (required) | `BottomNavigationItem[]` |   |
| `value` | `string` | The active item's key. |
| `defaultValue` | `string` |   |
| `onValueChange` | `(key: string) => void` |   |
| `onReselect` | `(key: string) => void` | Tapping the active item again: scroll to top, refresh. |
| `labelVisibility` | `"always" \| "active" \| "never"` | Default `always`. |
| `safeArea` | `boolean` | Pad the bottom by the safe-area inset (home indicator, gesture bar). Default true. |
| `style` | `StyleProp<ViewStyle>` |   |
| `styles` | `Partial<{ root: StyleProp<ViewStyle>; item: StyleProp<ViewStyle>; indicator: StyleProp<…` |   |
| `localeText` | `Partial<BottomNavigationLocaleText>` |   |

## Notes

- Items are `role="tab"` with `aria-selected`; a badge is spoken with its label ("Invoices, 3 new").
- `onReselect` fires when the active item is tapped again, for scroll-to-top or refresh.
- Pads its bottom by `KitProvider`'s `insets.bottom`.
- Mobile only: there is no web version of this component.
