@rootnative/components
v0.0.0-alpha.14
Published
Material Design 3 UI components for React Native, part of RootNative UI.
Maintainers
Readme
@rootnative/components
Material Design 3 UI components for React Native, part of RootNative UI.
Install
pnpm add @rootnative/core @rootnative/components @rootnative/inertia react-native-safe-area-context react-native-reanimated react-native-worklets@rootnative/inertia is a required peer of both @rootnative/core and
@rootnative/components — every animation in the library runs on it. npm and
pnpm install required peers automatically; Yarn classic does not. The rest of
the packages above are optional peers, so no package manager installs them
for you.
Reanimated 4 runs on react-native-worklets (installed above). Expo SDK 54 bundles its Babel plugin — nothing to configure. On bare React Native, add 'react-native-worklets/plugin' last in your babel.config.js plugins.
Optional — only needed if you plan to use icons in your app:
pnpm add @expo/vector-iconsOptional — react-native-svg is only needed for the circular Progress variant:
pnpm add react-native-svg
react-native-reanimatedpowers state-layer transitions and gesture-driven components (Slider, Switch). Needed for any interactive component; static components (Typography, Layout, Portal, KeyboardAvoidingWrapper, Divider) work without it. It is declared as an optional peer, so nothing installs it for you. With Expo SDK 54 it's also already available in Expo Go.Note that peer dependencies are not installed automatically: these are optional peers, so npm/pnpm skip them too, and Yarn classic installs no peers at all. Install the blocks above explicitly.
Wrap your app with ThemeProvider from @rootnative/core (see @rootnative/core).
Import
Subpath imports (preferred for tree-shaking):
import { Button } from '@rootnative/components/button'
import { Card } from '@rootnative/components/card'Root import:
import { Button, Card } from '@rootnative/components'Components
| Component | Subpath | Variants |
|-----------|---------|----------|
| Typography | ./typography | displayLarge..labelSmall (15 MD3 type scale roles) |
| Button | ./button | filled, elevated, outlined, text, tonal |
| IconButton | ./icon-button | filled, tonal, outlined, standard |
| FAB | ./fab | primary, secondary, tertiary, surface · small, medium, large · optional extended label |
| ButtonGroup | ./button-group | standard, connected · single or multi-select toggle |
| AppBar | ./appbar | small, center-aligned, medium, large |
| Card | ./card | elevated, filled, outlined |
| Chip | ./chip | assist, filter, input, suggestion |
| Avatar | ./avatar | image, icon, or text initials · 5 sizes (xSmall..xLarge) |
| Checkbox | ./checkbox | — |
| Radio | ./radio | — |
| Switch | ./switch | — |
| Slider | ./slider | continuous, discrete (stepped), range, centered origin |
| Progress | ./progress | linear, circular · determinate, indeterminate |
| LoadingIndicator | ./loading-indicator | contained, uncontained · determinate, indeterminate |
| TextField | ./text-field | filled, outlined |
| Layout | ./layout | Layout, Box, Row, Column, Grid |
| Dialog | ./dialog | basic, fullscreen · Icon / Title / Content / Actions slots |
| Divider | ./divider | horizontal, vertical · optional leading/trailing insets |
| List | ./list | List, ListItem, ListDivider (alias of Divider) |
| Portal | ./portal | Portal, PortalHost |
| Snackbar | ./snackbar | SnackbarProvider + useSnackbar() — imperative queue |
| Menu | ./menu | Menu, Menu.Item · self-managing or controlled · anchored with collision flipping |
| Tooltip | ./tooltip | plain, rich · hover or long press · anchored with collision flipping |
| BottomSheet | ./bottom-sheet | modal, standard · snap points · velocity-based settle · drag-to-dismiss |
| Tabs | ./tabs | primary, secondary · fixed or scrollable · sliding active indicator |
| NavigationBar | ./navigation-bar | 3–5 destinations · label visibility always / selected / never |
| KeyboardAvoidingWrapper | ./keyboard-avoiding-wrapper | — |
Quick examples
import { Button } from '@rootnative/components/button'
import { TextField } from '@rootnative/components/text-field'
import { Card } from '@rootnative/components/card'
import { Typography } from '@rootnative/components/typography'
import { Row, Column } from '@rootnative/components/layout'
// Button with icon
<Button variant="filled" leadingIcon="plus" onPress={handleCreate}>Create</Button>
// Text field
<TextField label="Email" variant="outlined" value={email} onChangeText={setEmail} />
// Card
<Card variant="elevated" onPress={handlePress}>
<Typography variant="titleMedium">Card Title</Typography>
</Card>
// Layout
<Column gap="md">
<Row gap="sm" align="center">
<Button variant="filled">Save</Button>
<Button variant="outlined">Cancel</Button>
</Row>
</Column>Override pattern
All interactive components support a 3-tier override system (theme → variant → props):
containerColor— Background color (state-layer colors auto-derived)contentColor— Content (label + icons) colorlabelStyle— Text-specific style (does not affect icons)style— Root container style
<Button containerColor="#006A6A" contentColor="#FFFFFF">Custom</Button>Icons
Every icon prop (leadingIcon, trailingIcon, icon, …) accepts an IconSource — one of three forms:
- String name (
"check") — resolves through the theme'siconResolver. By default this is MaterialCommunityIcons from@expo/vector-icons. - ReactElement (
<Check size={18} color="#fff" />) — one-off icon from any library; you control size and color. - Render function (
({ size, color }) => <Check ... />) — receives the component's resolved size and color.
To route string names to a different library app-wide (Lucide, Phosphor, SF Symbols, custom SVGs), pass an iconResolver to ThemeProvider. Pre-built adapters live in @rootnative/icons — see the icons guide.
Docs
Full API reference: https://rootnative.github.io/ui/
LLM-optimized reference: https://rootnative.github.io/ui/llms-full.txt — or read node_modules/@rootnative/components/llms.txt for the exact installed version.
License
MIT
