Skip to main content

Overview

The YouVersion Platform SDK provides a comprehensive theming system built on Tailwind CSS v4 with automatic dark mode support, semantic color tokens, and scoped styling to prevent conflicts with your application’s styles.
All SDK styles are scoped using the yv: prefix and data-yv-sdk attributes, ensuring they don’t interfere with your app’s existing styles.

Quick Start

Set Theme Mode

Configure the theme when setting up the YouVersion provider:
import { YouVersionProvider } from '@youversion/platform-react-hooks';

function App() {
  return (
    <YouVersionProvider
      appKey="your-app-key"
      theme="dark"  // "light" | "dark" | "system"
    >
      <MyApp />
    </YouVersionProvider>
  );
}
Available theme modes:
  • "light" - Force light mode
  • "dark" - Force dark mode
  • "system" - Follow system preferences (default)

System Theme Detection

When using theme="system", the SDK automatically detects and responds to system theme changes:
// The SDK listens to prefers-color-scheme media query
window.matchMedia('(prefers-color-scheme: dark)').matches
The theme updates automatically when users change their system preferences - no page reload required.

Tailwind CSS Integration

Auto-Injected Styles

The UI package automatically injects its styles when imported:
import { BibleReader } from '@youversion/platform-react-ui';
// Styles are automatically injected on import
This happens through a side effect in the entry point (src/index.ts):
import { injectStyles } from './lib/injectStyles';

// Styles are embedded as __YV_STYLES__ constant via build-time replacement
injectStyles();
No CSS files to import manually. No build steps required. Just import and use.

Scoped Class Prefix

All Tailwind classes use the yv: prefix to prevent naming collisions:
// SDK classes are prefixed
<div className="yv:mt-4 yv:text-foreground yv:bg-background">
  Bible content
</div>

// Your app's classes remain unprefixed
<div className="mt-4 text-gray-900 bg-white">
  Your content
</div>
This is configured in the build process:
/* global.css */
@import 'tailwindcss/theme.css' prefix(yv);
@import 'tailwindcss/utilities.css' prefix(yv);

Data Attribute Scoping

All SDK components include a data-yv-sdk attribute for additional scoping:
// All SDK components render with this attribute
<div data-yv-sdk data-yv-theme="dark">
  <BibleReader.Root>...</BibleReader.Root>
</div>
Styles are scoped to this attribute:
[data-yv-sdk] {
  /* SDK styles only apply inside this scope */
}

Color System

Semantic Tokens

The SDK uses semantic color tokens that automatically adapt to light/dark mode:
<div className="yv:bg-background yv:text-foreground">
  Adapts to theme automatically
</div>

<div className="yv:bg-card yv:text-card-foreground">
  Card with proper contrast
</div>

<div className="yv:bg-muted yv:text-muted-foreground">
  Muted/secondary content
</div>

<button className="yv:bg-primary yv:text-primary-foreground">
  Primary action
</button>

<button className="yv:bg-destructive yv:text-destructive-foreground">
  Delete action
</button>

Available Semantic Tokens

TokenUsageLight ModeDark Mode
backgroundMain backgroundWhiteGray-50
foregroundMain textGray-50White
cardCard backgroundsGray-2Gray-45
card-foregroundCard textGray-50White
popoverPopover backgroundsWhiteGray-48
popover-foregroundPopover textGray-50White
primaryPrimary actionsGray-50Red (YV brand)
primary-foregroundPrimary action textWhiteWhite
secondarySecondary actionsWarm-neutralWarm-neutral-dm
mutedMuted backgroundsGray-5Gray-40
muted-foregroundMuted textGray-30Gray-10
accentAccent backgroundsGray-5Gray-30
destructiveDelete/error actionsRedRed
borderBordersGray-15Gray-35
inputInput backgroundsGray-5Gray-40
ringFocus ringsBlue-30Blue-30-dm
Always use semantic tokens instead of arbitrary colors:
  • yv:bg-background
  • yv:text-muted-foreground
  • yv:bg-white
  • yv:text-gray-500
Semantic tokens ensure proper contrast and automatic theme adaptation.

YouVersion Design System Colors

The SDK includes the complete YouVersion design system color palette:
--yv-red: oklch(0.64 0.22 15);
--yv-red-dark-mode: oklch(0.68 0.19 15);
--yv-warm-neutral: oklch(0.96 0.005 20);
--yv-warm-neutral-dm: oklch(0.25 0.005 20);
All colors use OKLCH color space for perceptually uniform brightness across hues.

Dark Mode Implementation

Dark mode is controlled by the data-yv-theme attribute:
// Light mode
<div data-yv-sdk data-yv-theme="light">
  ...
</div>

// Dark mode
<div data-yv-sdk data-yv-theme="dark">
  ...
</div>
The CSS automatically switches tokens:
[data-yv-sdk] {
  --yv-background: var(--yv-white);
  --yv-foreground: var(--yv-gray-50);
}

[data-yv-sdk][data-yv-theme='dark'] {
  --yv-background: var(--yv-gray-50);
  --yv-foreground: var(--yv-white);
}

Custom Dark Mode Styles

Use the dark: variant to apply dark-mode-specific styles:
@custom-variant dark (&:is([data-yv-sdk][data-yv-theme='dark'] *));
In components:
<div className="yv:bg-white dark:yv:bg-gray-900">
  Custom dark mode styling
</div>

Typography

The SDK includes two web fonts:
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;700&family=Source+Serif+4:wght@400;700&display=swap');
Available font families:
  • --yv-font-sans: ‘Inter’, sans-serif (default)
  • --yv-font-serif: ‘Source Serif 4’, serif (for Bible text)
Use them in components:
<div className="yv:font-sans">
  UI text in Inter
</div>

<div className="yv:font-serif">
  Bible text in Source Serif 4
</div>

Customizing Component Styles

Using Background Prop

Most components accept a background prop:
<BibleReader.Root background="dark">
  <BibleReader.Content />
</BibleReader.Root>
This sets the data-yv-theme attribute on the component root.

Custom Styling with Tailwind

You can add your own utility classes alongside SDK classes:
import { BibleCard } from '@youversion/platform-react-ui';

function CustomCard() {
  return (
    <div className="my-custom-wrapper">
      <BibleCard
        reference="JHN.3.16"
        versionId={3034}
        background="light"
      />
    </div>
  );
}

Overriding SDK Styles

Since SDK styles are scoped to [data-yv-sdk], you can override them with higher specificity:
/* Your app's CSS */
.my-custom-bible-reader [data-yv-sdk] {
  --yv-background: #f0f0f0;
  --yv-foreground: #333;
}
Or use inline styles:
<div style={{ '--yv-background': '#f0f0f0' } as React.CSSProperties}>
  <BibleReader.Root>...</BibleReader.Root>
</div>

CSS Variables Reference

All theme variables are exposed as CSS custom properties:
[data-yv-sdk] {
  /* Semantic tokens */
  --yv-background: var(--yv-white);
  --yv-foreground: var(--yv-gray-50);
  --yv-card: var(--yv-gray-2);
  --yv-primary: var(--yv-gray-50);
  --yv-border: var(--yv-gray-15);
  
  /* Radius */
  --yv-radius: 2rem;
  --radius-sm: calc(var(--yv-radius) - 4px);
  --radius-md: calc(var(--yv-radius) - 2px);
  --radius-lg: var(--yv-radius);
  --radius-xl: calc(var(--yv-radius) + 4px);
  
  /* Fonts */
  --font-sans: 'Inter', sans-serif;
  --font-serif: 'Source Serif 4', serif;
}
Access these in your components:
<div style={{ 
  backgroundColor: 'var(--yv-background)',
  color: 'var(--yv-foreground)',
  borderRadius: 'var(--yv-radius)'
}}>
  Custom styled element
</div>

Preflight/Reset Styles

The SDK includes a scoped version of Tailwind’s Preflight (CSS reset):
:where([data-yv-sdk]) {
  *,
  ::after,
  ::before {
    box-sizing: border-box;
    margin: 0;
    padding: 0;
    border: 0 solid;
  }
  /* ... more reset styles */
}
The :where() pseudo-class ensures these resets have zero specificity, so they won’t override your app’s styles. They only provide a baseline for SDK components.

Build Process

The theming system is built in three steps:
pnpm build:css    # Tailwind CSS compilation
pnpm build:js     # tsup bundling with style injection
pnpm build:types  # TypeScript declarations
What happens:
  1. build:css - Tailwind compiles src/styles/global.cssdist/tailwind.css
  2. build:js - tsup reads dist/tailwind.css and injects it as __YV_STYLES__ constant
  3. On import - injectStyles() creates a <style> tag with the embedded CSS
// Simplified version of injectStyles()
function injectStyles() {
  if (typeof document === 'undefined') return;
  
  const styleId = 'yv-platform-sdk-styles';
  if (document.getElementById(styleId)) return;
  
  const style = document.createElement('style');
  style.id = styleId;
  style.textContent = __YV_STYLES__; // Injected at build time
  document.head.appendChild(style);
}

Accessibility

The theming system ensures accessibility:
  • Sufficient contrast - All color combinations meet WCAG AA standards
  • Focus indicators - Visible focus rings using --yv-ring
  • Semantic colors - Destructive actions use red, success uses green
  • High contrast mode - Works with Windows High Contrast mode

Advanced Customization

Creating Custom Themes

You can create completely custom themes by overriding CSS variables:
function CustomThemedApp() {
  return (
    <div
      data-yv-sdk
      data-yv-theme="dark"
      style={{
        '--yv-background': '#1a1a2e',
        '--yv-foreground': '#eee',
        '--yv-primary': '#0f3460',
        '--yv-accent': '#16213e',
        '--yv-border': '#533483',
      } as React.CSSProperties}
    >
      <BibleReader.Root versionId={3034} book="JHN" chapter="1">
        <BibleReader.Content />
      </BibleReader.Root>
    </div>
  );
}

Component-Specific Styling

Target specific components with CSS:
/* Style all Bible readers */
[data-yv-sdk] .bible-reader-root {
  --yv-background: #fafafa;
}

/* Style verse numbers */
[data-yv-sdk] .verse-number {
  color: var(--yv-muted-foreground);
  font-size: 0.875rem;
}

Troubleshooting

Styles Not Applying

Problem: SDK styles don’t appear Solution: Ensure you’re importing from the UI package:
// ✅ Correct - imports and injects styles
import { BibleReader } from '@youversion/platform-react-ui';

// ❌ Wrong - hooks don't include styles
import { useChapter } from '@youversion/platform-react-hooks';

Style Conflicts

Problem: SDK styles conflict with your app’s styles Solution: All SDK classes should use the yv: prefix. If conflicts occur:
  1. Check that SDK components have data-yv-sdk attribute
  2. Verify Tailwind config doesn’t have overlapping prefixes
  3. Increase specificity of your app’s styles if needed

Dark Mode Not Switching

Problem: Theme doesn’t change when toggled Solution: Ensure theme prop is passed to YouVersionProvider:
<YouVersionProvider
  appKey="your-app-key"
  theme="dark"  // ← Required for dark mode
>
  <App />
</YouVersionProvider>

Next Steps

Components

Explore all UI components and their styling options

Styling

Learn advanced customization techniques

Build docs developers (and LLMs) love