@hikari/ui-native
Shared React Native component library for mobile apps in the monorepo. Built on gluestack-ui v3 with NativeWind for Tailwind CSS styling on native platforms.
Storybook: ui-native-storybook-web.pages.dev
Installation
Already available to all workspace apps. Add the dependency:
{
"dependencies": {
"@hikari/ui-native": "workspace:*"
}
}
Wrap your app with the provider:
import { GluestackUIProvider } from "@hikari/ui-native/provider";
export default function App() {
return (
<GluestackUIProvider mode="light">{/* your app */}</GluestackUIProvider>
);
}
Usage
import {
Button,
ButtonText,
Card,
Heading,
Text,
VStack,
} from "@hikari/ui-native";
function MyScreen() {
return (
<Card className="gap-2 p-4">
<Heading size="md">Dashboard</Heading>
<Text>Everything is running smoothly.</Text>
<Button action="primary" variant="solid" size="md">
<ButtonText>View Details</ButtonText>
</Button>
</Card>
);
}
Deep imports
import { Button, ButtonText } from "@hikari/ui-native/components/ui/button";
Components (52)
| Category | Components |
|---|---|
| Layout | Box, Center, Grid, GridItem, HStack, VStack, View, Divider, SafeAreaView, KeyboardAvoidingView, ScrollView, Portal |
| Typography | Heading, Text, Link, LinkText |
| Forms | Button, Checkbox, FormControl, Input, InputField, Radio, Select, Slider, Switch, Textarea |
| Data Display | Accordion, Avatar, Badge, Card, Icon, Image, ImageBackground, Progress, Skeleton, Spinner, Table |
| Feedback | Alert, Toast, FAB |
| Overlays | Actionsheet, AlertDialog, BottomSheet, Drawer, Menu, Modal, Popover, Tooltip |
| Lists | FlatList, SectionList, VirtualizedList |
| Platform | InputAccessoryView, StatusBar, RefreshControl, Pressable |
Variant system
Components use gluestack-ui's tva() (Tailwind Variant Authority) for variant props. Common patterns:
| Prop | Values | Used by |
|---|---|---|
action | primary, secondary, positive, negative, error, warning, success, info, muted | Button, Badge, Alert, Toast |
variant | solid, outline, link, filled, unfilled, ghost, elevated | Button, Badge, Alert, Card, Accordion |
size | xs, sm, md, lg, xl, 2xl | Button, Input, Badge, Avatar, Modal, Heading, Text |
space | xs, sm, md, lg, xl, 2xl, 3xl, 4xl | HStack, VStack |
orientation | horizontal, vertical | Divider, Slider, Progress |
Per-app theming
The default color palette is defined in src/components/ui/gluestack-ui-provider/config.ts using NativeWind's vars() function. Each color scale (primary, secondary, error, success, etc.) has shades from 0–950 as RGB triplets.
Overriding colors
To customize the theme in your app, create a custom config and pass it as a style to the provider's root View:
import { vars } from "nativewind";
import { UiNativeProvider } from "@hikari/ui-native/provider";
const appTheme = {
light: vars({
// Override primary to teal
"--color-primary-500": "13 148 136",
"--color-primary-600": "15 118 110",
"--color-primary-700": "19 78 74",
// ... only override the shades you need
}),
dark: vars({
"--color-primary-500": "45 212 191",
"--color-primary-600": "94 234 212",
"--color-primary-700": "153 246 228",
}),
};
export default function App() {
const mode = "light"; // or "dark" or "system"
return (
<UiNativeProvider
mode={mode}
style={appTheme[mode === "system" ? "light" : mode]}
>
{/* your app */}
</UiNativeProvider>
);
}
NativeWind vars() values cascade through the React Native view tree, so vars set on a parent override those set higher up (like the default provider config).
Available color scales
| Scale | CSS variable pattern | Usage |
|---|---|---|
primary | --color-primary-{0-950} | Primary buttons, active states |
secondary | --color-secondary-{0-950} | Secondary surfaces, muted elements |
tertiary | --color-tertiary-{0-950} | Tertiary accents |
error | --color-error-{0-950} | Error states, destructive actions |
success | --color-success-{0-950} | Success feedback |
warning | --color-warning-{0-950} | Warning states |
info | --color-info-{0-950} | Informational highlights |
typography | --color-typography-{0-950} | Text colors |
outline | --color-outline-{0-950} | Borders and outlines |
background | --color-background-{0-950} | Surface backgrounds |
Special background tokens: --color-background-error, --color-background-warning, --color-background-success, --color-background-muted, --color-background-info.
Focus ring indicators: --color-indicator-primary, --color-indicator-info, --color-indicator-error.
Design system documentation
Each app with significant native UI should have a DESIGN-SYSTEM.md at its root documenting the color palette, typography, spacing, and component patterns used. This serves as the source of truth for the app's visual language.
Adding or upgrading components
# Add a new gluestack component
pnpm --filter @hikari/ui-native ui:add
# Upgrade existing components
pnpm --filter @hikari/ui-native ui:upgrade
# Run postprocessing (code transforms for NativeWind compat)
pnpm --filter @hikari/ui-native ui:postprocess
Tech stack
- UI Framework: gluestack-ui v3
- Styling: NativeWind (Tailwind CSS for React Native), Tailwind v3
- Animations: @legendapp/motion (framer-motion equivalent for RN)
- Bottom Sheet: @gorhom/bottom-sheet
- Icons: Lucide React Native
- Gestures: react-native-gesture-handler, react-native-reanimated
Storybook
The component library is documented and tested via two Storybook setups:
Web preview (primary)
- App:
apps/ui-native-storybook-web - Framework:
@storybook/react-native-web-vite(renders native components via react-native-web) - URL: ui-native-storybook-web.pages.dev
- Coverage: 52 story files, 125 stories covering all variants and sizes
- Tests: Vitest coverage tests (component-to-story mapping) + Playwright e2e (all stories render without errors)
- Key config:
jsxImportSource: "nativewind"for CSS interop, esbuild plugin to stubInputAccessoryView, ESM alias for@legendapp/motion
On-device preview
- App:
apps/ui-native-playground(Expo with on-device Storybook via@storybook/react-native) - Purpose: Verify components on actual iOS/Android devices with native gestures and animations
A coverage test in apps/ui-native-storybook-web/test/storybook-coverage.test.ts ensures both storybook setups stay in sync with the package's component exports.