Skip to main content

App shell and providers

The app shell creates one OvokClient and makes it available to routes that use the SDK. Provider ownership is explicit: @ovok/core supplies the client context, @ovok/native supplies the mobile UI theme and feature components, and your app supplies navigation and any app-wide services.

Use this page after installation and native setup. For a minimal working sign-in app, follow the quick start; this guide explains where each provider belongs as the app grows.

Provider tree​

For an Expo Router app, a typical root looks like this:

KeyboardProvider
└── GestureHandlerRootView
└── OvokProvider @ovok/core
└── ThemeProvider @ovok/native
└── BottomSheetModalProvider optional peer provider
└── Navigation ThemeProvider
└── App routes

Add optional app providers, such as query-cache persistence or localization, where their context is needed. Keep feature providers close to the routes that use them; Bluetooth scans and health authorization should not start just because the app shell mounted.

Initialize the client outside React renders​

Initialize the runtime from the entry module before importing this layout, as shown in Polyfills and runtime setup. This example assumes that bootstrap has already run. Keep both the client and storage adapter at module scope so a route render does not recreate the client's identity or session storage.

Put the initializer in a module such as ovok-client.ts; have the root layout and other app services import that same client instance.

import { OvokClient } from "@ovok/core";
import { ExpoClientStorage } from "@ovok/native";

const baseUrl = process.env.EXPO_PUBLIC_OVOK_BASE_URL;
if (!baseUrl) {
throw new Error("Set EXPO_PUBLIC_OVOK_BASE_URL in your app environment");
}

export const ovokClient = new OvokClient({
baseUrl,
fhirUrlPath: "/fhir",
storage: new ExpoClientStorage(),
});

Use your app's environment setup for baseUrl and optional client configuration. Expo embeds EXPO_PUBLIC_ values in the app bundle, so they are suitable for public configuration only. See Installation for native dependencies and Authentication for session behavior.

Compose the Expo Router root​

This example follows the provider boundaries used by the reference app. The SDK theme is separate from the navigation theme, even when both use the same brand palette.

import { BottomSheetModalProvider } from "@gorhom/bottom-sheet";
import { OvokProvider } from "@ovok/core";
import {
DEFAULT_COLORS,
DEFAULT_MULTIPLIERS,
ThemeProvider as OvokThemeProvider,
} from "@ovok/native";
import {
DefaultTheme,
Stack,
ThemeProvider as NavigationThemeProvider,
} from "expo-router";
import type { PropsWithChildren } from "react";
import { GestureHandlerRootView } from "react-native-gesture-handler";
import { KeyboardProvider } from "react-native-keyboard-controller";

import { ovokClient } from "./ovok-client";

function SdkProviders({ children }: PropsWithChildren) {
return (
<OvokProvider client={ovokClient}>
<OvokThemeProvider
theme={{
colors: DEFAULT_COLORS,
dark: false,
spacingMultiplier: DEFAULT_MULTIPLIERS.spacing,
borderRadiusMultiplier: DEFAULT_MULTIPLIERS.borderRadius,
}}
>
<BottomSheetModalProvider>
<NavigationThemeProvider value={DefaultTheme}>
{children}
</NavigationThemeProvider>
</BottomSheetModalProvider>
</OvokThemeProvider>
</OvokProvider>
);
}

export default function RootLayout() {
return (
<KeyboardProvider>
<GestureHandlerRootView style={{ flex: 1 }}>
<SdkProviders>
<Stack />
</SdkProviders>
</GestureHandlerRootView>
</KeyboardProvider>
);
}

OvokProvider is exported by @ovok/core; the SDK ThemeProvider is exported by @ovok/native. Rename the latter on import when using another provider with the same name. BottomSheetModalProvider is imported directly from @gorhom/bottom-sheet; mount it once when a screen uses SDK bottom sheets such as PickerSheet or DataSync.ManuallyRequestSheet.

If you use SafeAreaProvider, a persisted query client, localization, error reporting, or app configuration context, add those providers where their hooks and components need them. The reference app places GestureHandlerRootView around navigation and uses the keyboard provider above it.

Configure the SDK theme​

ThemeProvider applies the React Native Paper theme, loads the bundled DM Sans fonts, and provides device-list context used by the supported-device UI. Its theme prop contains:

PropertyPurpose
colorsPaper colors plus the SDK's semantic and indexed color palette; start with DEFAULT_COLORS and override values your app uses.
darkWhether the SDK theme is in dark mode.
spacingMultiplierSpacing scale; DEFAULT_MULTIPLIERS.spacing is the baseline.
borderRadiusMultiplierCorner-radius scale; DEFAULT_MULTIPLIERS.borderRadius is the baseline.

Read the active theme with useAppTheme. Navigation has its own color shape and must receive a navigation theme separately; map the brand colors to navigation's primary, background, card, text, border, and notification values rather than passing the SDK color object directly.

The SDK theme provider returns null while its fonts load. Account for that initial render in the app's launch experience; the provider does not accept a loading fallback prop.

Place feature providers near their screens​

Mount these providers only for flows that use them:

ProviderPlace itWhat to keep in mind
BTProviderAround the Bluetooth screen or flowPass a long-lived BleManager and the accepted device declarations. Unmounting stops the provider-owned scan and tears down its managed devices.
DataSync.AppleHealthAuthorizationProviderAround the iOS Health import screenRequest only the HealthKit identifiers the feature reads or writes.
DataSync.AndroidHealthConnectAuthorizationProviderAround the Android Health Connect screenDeclare platform record permissions in native app configuration as well as in the authorization flow.
SocketProviderAround screens that use socket contextKeep the URL, authentication policy, subscriptions, and reconnect UX app-owned.

Do not mount Bluetooth or health import providers globally unless the product intentionally keeps that workflow active across every route. See the Bluetooth guide, Health data guide, and Background sync for lifecycle and platform details.

Context requirements​

Render SDK features below the providers they use:

  • OvokProvider: authentication forms and account controls, patient and observation features that use the active client or patient, data-sync components, socket context, questionnaire submission helpers, and result handlers that use the client.
  • ThemeProvider: components that call useAppTheme, the device catalog list, and themed SDK UI.
  • BottomSheetModalProvider: SDK components that open a Gorhom bottom-sheet modal.
  • KeyboardProvider: keyboard-aware forms that use react-native-keyboard-controller.

When a component renders without expected data, check its provider ancestry and the current authentication or patient state before changing its props. See Architecture and lifecycle for the responsibilities of each boundary.