A React Native SDK for displaying Bible content in Expo apps on iOS and Android. It wraps the React Web SDK (@youversion/platform-react-ui) as Expo DOM Components, adding native affordances (bottom sheets, navigation, storage) through React Native.
- Features
- Requirements
- Installation
- Getting Started
- Usage
- Sample App
- Documentation
- Contributing
- Support
- License
- Scripture display: React Native components for Bible passages with
BibleTextViewandBibleCard - Bible Reader: a complete reading experience with
BibleReader, including built-in chapter and version pickers - Verse of the Day: built-in
VerseOfTheDaycomponent - Sign in: optional PKCE OAuth via
YouVersionProvideranduseYVAuth(@youversion/platform-react-native-expo-core) - Theming:
light/dark/systemthemes, with per-component overrides - Native presentation: footnotes, chapter, and version pickers open in native bottom sheets via
@gorhom/bottom-sheet
- Expo SDK 56
- A YouVersion Platform API key (register here)
Note: This SDK requires a dev build (not Expo Go) due to native module dependencies.
npx expo install @youversion/platform-react-native-expo-ui @youversion/platform-react-native-expo-coreThe UI package depends on core at runtime; install both so TypeScript resolves @youversion/platform-react-native-expo-core when you use auth APIs.
Install the required peer dependencies (Expo will pick versions compatible with your SDK):
npx expo install @gorhom/bottom-sheet @expo/dom-webview \
expo-application expo-crypto expo-secure-store expo-web-browser \
react-dom \
react-native-gesture-handler react-native-mmkv \
react-native-nitro-modules react-native-reanimated \
react-native-safe-area-context react-native-svg \
react-native-workletsExpo, React, and React Native are also peer dependencies, but they are expected to be provided by your Expo app.
See packages/ui/package.json and packages/core/package.json peerDependencies for the canonical lists.
- Get your app key: register your app with YouVersion Platform to acquire one.
- Wrap your app root with
YouVersionProvider:
import { YouVersionProvider } from '@youversion/platform-react-native-expo-ui'
import { GestureHandlerRootView } from 'react-native-gesture-handler'
export default function RootLayout() {
const appKey = process.env.EXPO_PUBLIC_YOUVERSION_APP_KEY
if (!appKey) return null
return (
<GestureHandlerRootView style={{ flex: 1 }}>
<YouVersionProvider appKey={appKey} theme="system">
{/* your app */}
</YouVersionProvider>
</GestureHandlerRootView>
)
}GestureHandlerRootView must wrap YouVersionProvider — the provider includes internal bottom-sheet support that depends on React Native Gesture Handler.
YouVersionProvider accepts theme="light" | "dark" | "system" and defaults to "system", which follows the device color scheme (falling back to "light" when the device scheme is unavailable). Components below can override the provider theme for that instance.
Native SDK strings follow the device locale by default; see the localization guide for details and the locale override.
Display a verse range or single verse with BibleTextView:
import { BibleTextView } from '@youversion/platform-react-native-expo-ui'
function VerseScreen() {
return (
<BibleTextView
reference="JHN.3.16" // USFM reference: BOOK.CHAPTER.VERSE (or VERSE-VERSE for a range)
versionId={3034} // 3034 = Berean Standard Bible (BSB); find other IDs at platform.youversion.com
/>
)
}showVerseNumbers (default true) controls whether verse numbers render inline.
Display a Bible card with a verse and reader controls:
import { BibleCard } from '@youversion/platform-react-native-expo-ui'
// 3034 = Berean Standard Bible (BSB); find other IDs at platform.youversion.com
function CardScreen() {
return <BibleCard reference="JHN.3.16" defaultVersionId={3034} />
}defaultVersionId is uncontrolled — the user's version choice is persisted on device. For controlled usage, pass versionId with onVersionChange instead. The version picker button is hidden by default (matching the React Web SDK); pass showVersionPicker to enable it, and note that onVersionPickerPress only fires when showVersionPicker is set. Embeds size themselves to their content by default (matchContents); pass dom={{ matchContents: false }} to opt out and size with flex styles. See the quick start for more.
Note: Scripture content is fetched from YouVersion servers; the underlying WebView caches responses for repeat reads.
BibleReader gives you a full Bible reading experience, ready to drop in as a tab or full screen:
import { BibleReader } from '@youversion/platform-react-native-expo-ui'
// 3034 = Berean Standard Bible (BSB); find other IDs at platform.youversion.com
function ReaderScreen() {
return <BibleReader defaultVersionId={3034} />
}BibleReader is stateful — it owns the current versionId and coordinates its built-in chapter and version picker sheets.
To present your own picker UI instead of the built-in sheets, pass onChapterPickerPress or onVersionPickerPress. The built-in sheet is suppressed and you receive the current selection:
<BibleReader
defaultVersionId={3034}
onVersionPickerPress={({ versionId, languageId }) => {
// present your own version picker
}}
/>The standalone sheets are also exported (BibleChapterPickerSheet, BibleVersionPickerSheet, BibleReaderSettingsSheet) for advanced flows.
import { VerseOfTheDay } from '@youversion/platform-react-native-expo-ui'
// 3034 = Berean Standard Bible (BSB); find other IDs at platform.youversion.com
function VotdScreen() {
return <VerseOfTheDay versionId={3034} />
}Authentication is optional. Pass an auth config to YouVersionProvider to enable it. After the user signs in, the browser redirects back to your app at the redirectUri you configure below, so your app needs a route at that path to receive the redirect and finish sign-in. With Expo Router, that means a screen whose path matches the redirect (e.g. app/callback.tsx); the example app's implementation is a copyable reference: apps/example/app/callback.tsx.
The redirectUri is where the browser sends the user back after sign-in. Linking.createURL('callback') (from expo-linking — install it with npx expo install expo-linking) builds it from your app's URL scheme: in a dev build it produces <your-scheme>://callback, where <your-scheme> is the scheme in your app.json. The example app's scheme is yvp-rn-example, so its redirect URI is yvp-rn-example://callback. Register that exact URI as a Callback URI for your app key in the YouVersion Platform console.
Choose a scheme unique to your app: on Android, multiple apps registering the same scheme triggers the system disambiguation dialog (an app chooser), and on iOS there is no defined process for which app gets the scheme — the OS silently picks one.
import { YouVersionProvider } from '@youversion/platform-react-native-expo-ui'
import * as Linking from 'expo-linking'
import { GestureHandlerRootView } from 'react-native-gesture-handler'
export default function RootLayout() {
const appKey = process.env.EXPO_PUBLIC_YOUVERSION_APP_KEY
const redirectUri = Linking.createURL('callback')
if (!appKey) return null
return (
<GestureHandlerRootView style={{ flex: 1 }}>
<YouVersionProvider appKey={appKey} auth={{ redirectUri, scopes: ['profile', 'email'] }}>
{/* your app */}
</YouVersionProvider>
</GestureHandlerRootView>
)
}For sign-in UI, drop in YouVersionAuthButton — it renders the branded Sign in with YouVersion button and handles sign-in/sign-out for you:
import { YouVersionAuthButton } from '@youversion/platform-react-native-expo-ui'
function ProfileScreen() {
return <YouVersionAuthButton />
}It accepts mode ('auto' | 'signIn' | 'signOut', default 'auto' toggles based on auth state), background ('light' | 'dark'), outline, radius ('rounded' | 'rectangular'), size ('default' | 'short' | 'icon'), and text (string, replaces the default localized label).
To build custom UI instead, use the useYVAuth hook:
import { useYVAuth } from '@youversion/platform-react-native-expo-core'
import { Button } from 'react-native'
function SignInButton() {
const { isAuthenticated, isLoading, signIn, signOut } = useYVAuth()
if (isLoading) return null
if (isAuthenticated) {
return <Button title="Sign out" onPress={() => signOut()} />
}
return <Button title="Sign in with YouVersion" onPress={() => signIn()} />
}Calling useYVAuth() requires that the surrounding YouVersionProvider received an auth config — without it the hook throws. Tokens are stored in expo-secure-store; profile metadata is cached in MMKV. See apps/example for a working callback route and Profile tab.
Explore the apps/example directory for a sample Expo Router app demonstrating:
- Bible reader integration
- Bible card and Scripture display
- Verse of the Day
- PKCE sign-in, OAuth callback handling, and the Profile tab
- Provider and native dependency setup
Set EXPO_PUBLIC_YOUVERSION_APP_KEY in your environment or an .env file before starting the example app.
To run it:
git clone https://github.com/youversion/platform-sdk-reactnative-expo.git
cd platform-sdk-reactnative-expo
pnpm install
# Build the dev client (first time)
cd apps/example
pnpm build:ios # or: pnpm build:android
# Subsequent runs
pnpm exec expo start --dev-clientSee the Contributing Guide for additional local development setup.
- React Native (Expo) SDK Guide: quick start and integration guide for this SDK
- API Documentation: REST API reference for advanced integration patterns and endpoints
- Sample Code: working example app and provider setup
Note
We are not yet accepting pull requests from external contributors. In the meantime, we welcome you to use the SDK, report bugs via GitHub Issues, and share feedback.
For internal development, see the Contributing Guide.
- Issues: GitHub Issues
- Platform Support: YouVersion Platform
This SDK is licensed under the Apache License 2.0. See LICENSE for details.
Made with ❤️ by YouVersion
