Preview App Install
Scan the QR code to open the Expo install page. This installs the latest internal development build on a provisioned device.
Prerequisites
Docyrus UI native components require an Expo project with React Native. Make sure your environment meets these requirements:
| Dependency | Minimum Version |
|---|---|
| React | 19 |
| React Native | 0.86 |
| Expo SDK | 57 |
| Node.js | 18 |
Install the CLI
Install the Docyrus CLI globally or use it via npx:
npm install -g @docyrus/cliAdd native components
Install native components using the rn- prefix:
# Install a native component
npx @docyrus/cli add rn-button
# Install multiple native components
npx @docyrus/cli add rn-button rn-input rn-card
# Install all native components
npx @docyrus/cli add --all-rnComponents are installed to your components/docyrus-native/ directory.
Install peer dependencies
Native components require Tailwind CSS v4 for React Native via Uniwind, plus common React Native libraries:
# Tailwind CSS v4 for React Native (required)
npx expo install uniwind tailwindcss
# Common peer dependencies
npx expo install react-native-svg
npx expo install react-native-reanimated react-native-worklets
npx expo install react-native-gesture-handler react-native-safe-area-contextDocyrus-connected components and every rn-hooks-* hook also need @tanstack/react-query (a required peer). Other native modules — expo-file-system, expo-sharing, expo-print, expo-clipboard, expo-image-picker, react-native-maps, react-native-webview, expo-speech-recognition, … — are optional peers: components load them lazily and degrade gracefully when they are missing. The CLI writes the peers a component needs into your peerDependencies; install them with npx expo install <name>.
Component styling also uses these packages (installed automatically by the CLI):
npm install tailwind-variants clsx tailwind-mergeSet up Uniwind
Docyrus Native components use className prop for styling via Uniwind — a build-time Tailwind CSS v4 integration for React Native.
1. Configure Metro
Add the Uniwind Metro plugin to your metro.config.js:
const { getDefaultConfig } = require('expo/metro-config');
const { withUniwindConfig } = require('uniwind/metro');
const config = getDefaultConfig(__dirname);
module.exports = withUniwindConfig(config, {
cssEntryFile: './src/styles/global.css',
// Docyrus components are designed on a 14px rem (text-sm, text-base, …)
polyfills: { rem: 14 }
});2. Create global CSS
Create a src/styles/global.css file with Tailwind, Uniwind and the Docyrus design tokens:
@import "tailwindcss";
@import "uniwind";
@import "./docyrus-native/index.css";The last line is required. Every native component is styled with semantic tokens (bg-background, text-muted-foreground, border-field-border, bg-success-soft, …) that are only defined by this file — without it components render transparent and unstyled. The CLI installs it with the first native component (the @docyrus/rn-styles item every rn-* component depends on) at src/styles/docyrus-native/index.css (styles/docyrus-native/ in the project root when there is no src/). It defines spacing, radius, font and light/dark color tokens; Uniwind follows the device appearance automatically. See Theming for the token list, overrides and the optional color schemes.
Import the tokens with a path relative to your CSS entry — adjust ./docyrus-native/index.css if your global.css lives elsewhere. In a pnpm/yarn workspace that depends on @docyrus/ui-native directly, @import "@docyrus/ui-native/styles"; also resolves. The optional color-schemes.css must always be imported by relative path: Uniwind reads theme variants from relatively imported files before it registers them, and a package import of that file fails with Cannot use @variant with unknown variant.
The tokens set --font-sans to Inter (Inter_400Regular, Inter_500Medium, …). Load those fonts with @expo-google-fonts/inter (useFonts), or override --font-sans* in an @theme block after the import.
3. Import in your app entry
Import the global CSS at the top of your root layout:
import '../styles/global.css';
import { DocyThemeProvider } from '@/lib/docyrus/theme';
export default function RootLayout() {
return (
<DocyThemeProvider>
{/* Your app content */}
</DocyThemeProvider>
);
}Set up the theme
Wrap your app with DocyThemeProvider at the root level. See the Theming guide for full configuration options.
import { DocyThemeProvider } from '@/lib/docyrus/theme';
export default function RootLayout() {
return (
<DocyThemeProvider defaultMode="system" defaultColorScheme="docyrus">
{/* Your app content */}
</DocyThemeProvider>
);
}Keyboard handling (recommended)
Form components like Input, Textarea, and Modal work best with react-native-keyboard-controller. It prevents inputs from being hidden behind the keyboard and provides smooth animated transitions.
npx expo install react-native-keyboard-controllerWrap your app with KeyboardProvider at the root level:
import '../styles/global.css';
import { KeyboardProvider } from 'react-native-keyboard-controller';
import { DocyThemeProvider } from '@/lib/docyrus/theme';
export default function RootLayout() {
return (
<KeyboardProvider>
<DocyThemeProvider>
{/* Your app content */}
</DocyThemeProvider>
</KeyboardProvider>
);
}Once the provider is active, all screens — including modals with KeyboardAvoidingView — automatically benefit from improved keyboard behavior.
Set up the Docyrus data layer
Skip this section if you only use presentational components. Docyrus-connected components (data grid, form view, calendar, kanban, composers, …) and the native hooks need a few providers near the root:
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { GestureHandlerRootView } from 'react-native-gesture-handler';
import Storage from 'expo-sqlite/kv-store';
import { DocyStorageProvider, type DocyKeyValueStore } from '@/lib/docyrus/storage';
import { UiTranslationProvider } from '@/hooks/docyrus-native/use-ui-translation';
import { DocyrusTenantProvider } from '@/hooks/docyrus-native/use-docyrus-tenant';
const queryClient = new QueryClient();
// Synchronous key-value backend for view-parameter persistence, saved views, recents, …
const store: DocyKeyValueStore = {
getItem: key => Storage.getItemSync(key),
setItem: (key, value) => Storage.setItemSync(key, value),
removeItem: key => Storage.removeItemSync(key)
};
export function DocyrusProviders({ client, authReady, t, children }) {
return (
<GestureHandlerRootView style={{ flex: 1 }}>
<QueryClientProvider client={queryClient}>
<DocyStorageProvider store={store}>
<UiTranslationProvider t={t}>
<DocyrusTenantProvider client={client} enabled={authReady}>
{children}
</DocyrusTenantProvider>
</UiTranslationProvider>
</DocyStorageProvider>
</QueryClientProvider>
</GestureHandlerRootView>
);
}QueryClientProvider— required by everyuse-docyrus-*hook.DocyrusTenantProvider— tenant date / number formats for every grid cell, value renderer and calendar (docs).DocyStorageProvider— persistent backend forpersistStateand the active saved view (docs). Without it state lives in memory for the process lifetime.UiTranslationProvider— optional; without it components render their English fallbacks (docs).GestureHandlerRootView— required by the calendar, notification stack, tree view drag and image editor.- Warm the shared inventory cache after sign-in with
useDocyrusInventoryLoader.
The Docyrus hooks require @docyrus/app-utils >= 0.20.0, which ships a React Native build (react-native export condition). No Metro config is needed for it.
Some optional peers need a development build (they are not in Expo Go): react-native-enriched-html (email composer rich body) and expo-speech-recognition (add its config plugin to app.config.ts). react-native-maps works in Expo Go, but an Android development build needs a Google Maps API key (android.config.googleMaps.apiKey).
Import and use
Once installed, import native components and use them in your screens. All components accept a className prop for Tailwind-based styling:
import { View } from 'react-native';
import { Button } from '@/components/docyrus-native/button';
export default function Home() {
return (
<View className="flex-1 justify-center p-4">
<Button variant="default" onPress={() => console.log('pressed')}>
Click me
</Button>
</View>
);
}Components are installed as source code — you can freely modify, extend, or restyle them to fit your needs.