OTFotf

Overview

The @otfdashkit/ui-native component surface — primitives, interface, layouts, patterns.

@otfdashkit/ui-native is the React Native side of the OTF design system. It's built on Tamagui and ships ~75 components across four buckets, plus a single header-collapse hook.

Buckets

BucketWhat's thereWhen to reach for it
Primitives5 Tamagui-styled atoms — Avatar, Button, Card, Input, TextBuilding from scratch
Interface14 building blocks — Badge, Dialog, Tabs, Toast, Tooltip, …Standard mobile UI
Layouts8 layout shells — ScreenLayout, Section, Grid, KeyboardStickyFooter, …Composing screens
Patterns48 high-level patterns — BottomSheet, OnboardingCarousel, PaywallScreen, ChipsTabBar, …Drop-in finished UX

Plus tamaguiDefaultConfig + createTamagui re-exports so you can wrap your own provider.

Importing

Every export sits at the package root:

import {
  // primitives
  Text, Card, Button, Input, Avatar,
  // interface
  Dialog, OtfTabs, Headings, Tooltip,
  // layouts
  ScreenLayout, Section, Grid,
  // patterns
  BottomSheet, ChipsTabBar, OnboardingCarousel,
  // provider
  OtfProvider, createTamagui, tamaguiDefaultConfig,
} from '@otfdashkit/ui-native'

Setup

Wrap your root layout with <OtfProvider> exactly once:

app/_layout.tsx
import {
  OtfProvider,
  OtfToastProvider,
  createTamagui,
  tamaguiDefaultConfig,
} from '@otfdashkit/ui-native'

const config = createTamagui(tamaguiDefaultConfig)

export default function RootLayout({ children }) {
  return (
    <OtfProvider config={config}>
      <OtfToastProvider>{children}</OtfToastProvider>
    </OtfProvider>
  )
}

Theming

The provider reads from @otfdashkit/tokens. To change theme at runtime, update Tamagui's theme name or pass theme="dark" | "light" on a <Theme> boundary. The kit does this via ThemeColorProvider + useThemeColor() — see the fitness-kit's contexts/ThemeContext.tsx for a copy-paste-ready setup.

API parity with @otfdashkit/ui

Where the abstraction is honest, names match across web and native:

  • Card, Avatar, Input, Button — same name, same prop intent
  • Tooltip, Tabs, Dialog, Toast — same name, same parts (prefixed Otf* on native to avoid clashing with Tamagui's own re-exports)

Where it isn't honest, names diverge:

  • Web Sheet → Native BottomSheet. Different gestures, different physics, different prop set.
  • Web Drawer → Native ActionSheet or BottomSheet. Pick by use case.
  • Web Toaster → Native OtfToastProvider + imperative toast().

Hooks

useCollapsibleHeader() — the only hook in this package. Pairs with <AppHeader> for the "shrink-on-scroll" header pattern from iOS / Material You.

import { AppHeader, useCollapsibleHeader } from '@otfdashkit/ui-native'

const { onScroll, headerHeight } = useCollapsibleHeader({ peakHeight: 96, base: 56 })

<AppHeader onScroll={onScroll} height={headerHeight} title="Summary" />

What's NOT in the box

  • Navigation library. Use Expo Router, React Navigation, or whatever matches your app. The patterns (ChipsTabBar, TabBar, AppHeader) are designed to plug into either.
  • Form library. Input, Selectable, WheelPicker are controlled primitives; bring your own state.
  • Native modules. Anything that needs a native build (camera, biometrics, push) is on you.

On this page