Skip to content
React NativeBeta

Tabs

A scrollable tab bar with a sliding indicator, and its panels.

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

On this page
Web preview — real device may differ
tsx
import { useState } from "react";
import { Text } from "react-native";
import { useKitTheme } from "@/component-lib/shared/native";
import { Tab, TabList, TabPanel, Tabs } from "@/component-lib/tabs";
import { Section } from "./layout"; // Section and Row: page layout for the demo
 
function Body({ children }: { children: string }) {
  const { tokens } = useKitTheme();
  return <Text style={{ color: tokens.fg, fontSize: tokens.fontSize, paddingVertical: 8 }}>{children}</Text>;
}
 
export function TabsDemo() {
  const [value, setValue] = useState("invoices");
  return (
    <>
      <Section title="Tabs · line (scrolls when it does not fit)">
        <Tabs value={value} onValueChange={setValue}>
          <TabList>
            <Tab value="overview">Overview</Tab>
            <Tab value="invoices" badge={12}>
              Invoices
            </Tab>
            <Tab value="payments">Payments</Tab>
            <Tab value="reports">Reports</Tab>
            <Tab value="settings">Settings</Tab>
            <Tab value="archived" disabled>
              Archived
            </Tab>
          </TabList>
          <TabPanel value="overview">
            <Body>Overview: revenue and outstanding at a glance.</Body>
          </TabPanel>
          <TabPanel value="invoices">
            <Body>12 invoices waiting for approval.</Body>
          </TabPanel>
          <TabPanel value="payments">
            <Body>Payments received this month.</Body>
          </TabPanel>
          <TabPanel value="reports">
            <Body>Reports: GST, TDS and ledgers.</Body>
          </TabPanel>
          <TabPanel value="settings">
            <Body>Settings for this workspace.</Body>
          </TabPanel>
        </Tabs>
      </Section>
 
      <Section title="Tabs · pills, small">
        <Tabs variant="pills" size="sm" defaultValue="week">
          <TabList>
            <Tab value="day">Day</Tab>
            <Tab value="week">Week</Tab>
            <Tab value="month">Month</Tab>
            <Tab value="year">Year</Tab>
          </TabList>
          <TabPanel value="day">
            <Body>Today's numbers.</Body>
          </TabPanel>
          <TabPanel value="week">
            <Body>This week's numbers.</Body>
          </TabPanel>
          <TabPanel value="month">
            <Body>This month's numbers.</Body>
          </TabPanel>
          <TabPanel value="year">
            <Body>This year's numbers.</Body>
          </TabPanel>
        </Tabs>
      </Section>
 
      <Section title="Tabs · enclosed (segmented), keepMounted">
        <Tabs variant="enclosed" keepMounted>
          <TabList>
            <Tab value="list">List</Tab>
            <Tab value="board">Board</Tab>
            <Tab value="calendar">Calendar</Tab>
          </TabList>
          <TabPanel value="list">
            <Body>No value given: the first tab is selected.</Body>
          </TabPanel>
          <TabPanel value="board">
            <Body>Board view; the list keeps its state while hidden.</Body>
          </TabPanel>
          <TabPanel value="calendar">
            <Body>Calendar view.</Body>
          </TabPanel>
        </Tabs>
      </Section>
 
      <Section title="Tabs · vertical">
        <Tabs orientation="vertical" defaultValue="profile">
          <TabList>
            <Tab value="profile">Profile</Tab>
            <Tab value="security">Security</Tab>
            <Tab value="billing">Billing</Tab>
          </TabList>
          <TabPanel value="profile">
            <Body>Name, photo and contact details.</Body>
          </TabPanel>
          <TabPanel value="security">
            <Body>Password and two-factor sign-in.</Body>
          </TabPanel>
          <TabPanel value="billing">
            <Body>Plan and payment method.</Body>
          </TabPanel>
        </Tabs>
      </Section>
    </>
  );
}

Install

npx @grampro/kit@native add Tabs

Usage

tsx
import { Tabs, TabList, Tab, TabPanel } from "@/component-lib/tabs";
 
<Tabs defaultValue="open">
  <TabList>
    <Tab value="open">Open</Tab>
    <Tab value="paid">Paid</Tab>
  </TabList>
  <TabPanel value="open">…</TabPanel>
  <TabPanel value="paid">…</TabPanel>
</Tabs>

Props

TabsProps

PropTypeDescription
valuestringSelected tab (controlled).
defaultValuestringSelected tab at first. Without either, the first enabled tab is selected.
onValueChange(value: string) => voidThe newly selected tab. Not fired when the same tab is pressed again.
orientationTabsOrientationDefault horizontal.
activationTabsActivationKept for API parity with the web. Touch has no arrow-key focus to follow, so a press always selects.
variantTabsVariantDefault line.
sizeTabsSizeDefault md.
keepMountedbooleanKeep hidden panels mounted, preserving their state (form input, scroll) through React's <Activity>. Default false.
childrenReactNode

Also accepts the props of Omit<ViewProps, "children">.

TabProps

PropTypeDescription
value (required)stringIdentifies the tab and its panel.
disabledboolean
iconReactNodeAn icon before the tab's text.
badgeReactNodeA small count or label after the text, e.g. unread items.
childrenReactNode
styleStyleProp<ViewStyle> | ((state: TabStyleState) => StyleProp<ViewStyle>)
stylesPartial<{ label: StyleProp<TextStyle>; badge: StyleProp<ViewStyle>; icon: StyleProp<Vie…

Also accepts the props of Omit<PressableProps, "children" | "style" | "disabled">.

TabPanelProps

PropTypeDescription
value (required)string
keepMountedbooleanOverrides keepMounted on Tabs for this panel.
childrenReactNode

Also accepts the props of Omit<ViewProps, "children">.

Native and web

  • activation is accepted for parity but a tap always selects.
  • Web version: Tabs on the web.