App shell and providers
The native package does not export a catch-all Provider. The canonical application shell uses OvokProvider from @ovok/core and the UI ThemeProvider from @ovok/native.
The example app's provider order is:
- KeyboardProvider
- OvokProvider
- ThemeProvider from @ovok/native
- BottomSheetModalProvider
- Ovok's re-exported BottomSheetModalProvider for SDK sheets
- Navigation's theme provider
- Your navigation and screens
The two bottom-sheet providers are intentionally distinct. The inner @ovok/native provider is required by SDK components that use the SDK's sheet implementation.
Minimal root layout
import { OvokClient, OvokProvider } from "@ovok/core";
import { BottomSheetModalProvider } from "@gorhom/bottom-sheet";
import { DefaultTheme, ThemeProvider } from "@react-navigation/native";
import {
BottomSheetModalProvider as OvokBottomSheetModalProvider,
DEFAULT_COLORS,
DEFAULT_MULTIPLIERS,
ExpoClientStorage,
ThemeProvider as OvokThemeProvider,
polyfillMedplumWebAPIs,
} from "@ovok/native";
import { Stack } from "expo-router";
import { KeyboardProvider } from "react-native-keyboard-controller";
polyfillMedplumWebAPIs();
const client = new OvokClient({
storage: new ExpoClientStorage(),
baseUrl: "https://api.ovok.com",
fhirUrlPath: "/fhir",
socialLoginClientId: process.env.EXPO_PUBLIC_OVOK_CLIENT_ID,
});
export default function RootLayout() {
return (
<KeyboardProvider>
<OvokProvider client={client}>
<OvokThemeProvider
theme={{
colors: DEFAULT_COLORS,
dark: false,
spacingMultiplier: DEFAULT_MULTIPLIERS.spacing,
borderRadiusMultiplier: DEFAULT_MULTIPLIERS.borderRadius,
}}
>
<BottomSheetModalProvider>
<OvokBottomSheetModalProvider>
<ThemeProvider value={DefaultTheme}>
<Stack />
</ThemeProvider>
</OvokBottomSheetModalProvider>
</BottomSheetModalProvider>
</OvokThemeProvider>
</OvokProvider>
</KeyboardProvider>
);
}
Use your app's environment system for URLs and client IDs. Never commit production credentials or copy the example app's values.
Theme contract
ThemeProvider accepts a theme with:
- colors, usually based on DEFAULT_COLORS;
- dark, the current color mode;
- spacingMultiplier, normally DEFAULT_MULTIPLIERS.spacing;
- borderRadiusMultiplier, normally DEFAULT_MULTIPLIERS.borderRadius.
Components read the resulting theme through useAppTheme(). Navigation has its own theme contract, so merge the same brand colors into the navigation theme separately.
Context requirement
The following features expect to be rendered below OvokProvider:
- auth forms and logout/account controls;
- patient and observation components that use the active profile;
- DataSync components;
- SocketProvider and socket hooks;
- questionnaire form submission helpers;
- Bluetooth result handlers that persist through the app's core client.
If a component renders but has no data, first verify provider order and the active patient/login state before changing component props.