Lynx/Modules/Navigation/Tabs
@sigx/lynx-navigation · Stable · Component library

Tabs#

A persistent native tab navigator. Each tab is declared with a <Tabs.Screen> and stays mounted while inactive (hidden with display:none), so per-tab state — including a nested back-stack — survives switching between tabs.

Import#

TSX
import { Tabs } from '@sigx/lynx-navigation';

Basic usage#

<Tabs initialTab> hosts one <Tabs.Screen name> per tab. Each Tabs.Screen body is rendered eagerly and kept mounted; only the active tab is visible. Drop a <Stack initialRoute> inside a Tabs.Screen to give that tab its own back-stack, and add a <TabBar /> for the default chrome:

TSX
import { Tabs, TabBar, Stack, Header } from '@sigx/lynx-navigation';

export const Main = () => (
  <Tabs initialTab="trips">
    <Tabs.Screen name="trips" label="Trips">
      <Stack initialRoute="tripsHome">
        <Header />
      </Stack>
    </Tabs.Screen>
    <Tabs.Screen name="account" label="Account">
      <Stack initialRoute="accountHome">
        <Header />
      </Stack>
    </Tabs.Screen>
    <TabBar />
  </Tabs>
);

Inside a tab, a card push (e.g. nav.push('tripDetail', { tripId })) stays in that tab's stack and the tab bar stays visible. modal / fullScreen / transparent-modal / sheet pushes escalate to the root navigator and overlay everything; nav.replace is always local.

Reading and switching the active tab#

Read the enclosing tab navigator with useTabs() — it returns { active, setActive(name), tabs }, all reactive. setActive ignores unknown tab names (no-op). It throws when called outside Tabs:

TSX
import { useTabs } from '@sigx/lynx-navigation';

export const TabSwitcher = () => {
  const tabs = useTabs();

  return (
    <view>
      <text>Active: {tabs.active}</text>
      {tabs.tabs.map((t) => (
        <text bindtap={() => tabs.setActive(t.name)}>
          {t.label ?? t.name}
        </text>
      ))}
    </view>
  );
};

Custom tab bar#

The default TabBar is headless and unstyled with accessibility wiring built in. Pass renderTab to override per-item rendering, or use NavTabBar from DaisyUI for a themed bar. Each Tabs.Screen's name, label, icon and accessibilityLabel flow through as the TabInfo for that tab.

Props#

Tabs#

PropTypeDescription
initialTabstringThe name of the tab shown first. Defaults to the first Tabs.Screen.

Tabs renders its default slot — the Tabs.Screen children plus the tab bar (TabBar or your own). It provides useTabs() to the subtree.

Tabs.Screen#

PropTypeDescription
namestringRequired. The tab identifier, captured once at setup (remount to rename).
iconIconSpec | JSXElementTab icon, surfaced via TabInfo to the tab bar.
labelstringHuman-readable tab label, surfaced via TabInfo.
accessibilityLabelstringAccessibility label for the tab, surfaced via TabInfo.

TabInfo#

The per-tab metadata derived from each Tabs.Screen, exposed through useTabs().tabs and passed to a custom TabBar renderTab:

FieldTypeDescription
namestringThe tab's identifier.
iconIconSpec | JSXElementThe tab's icon, if any.
labelstringThe tab's label, if any.
accessibilityLabelstringThe tab's accessibility label, if any.

See also#

  • useTabs — the reactive { active, setActive, tabs } handle.
  • TabBar — the default headless tab-bar chrome and its renderTab override.
  • Usage — tabs with per-tab stacks, modals and the full setup pattern.