React Native Theme TransitionReact Native Theme Transition

Types

Every TypeScript type exported by the library, with field-level reference.

The library exports its types as named imports. Most of them are inferred automatically from your theme map, so the only ones you typically write by hand are SetThemeOptions (when passing options through a wrapper) and ThemeTransitionConfig (when you split your config across files).

Reference

import type {
  ColorScheme,
  OriginSpec,
  SetThemeOptions,
  SystemThemeMap,
  ThemeDefinition,
  ThemeNames,
  ThemeTransitionAPI,
  ThemeTransitionConfig,
  TokenNames,
  TransitionOrigin,
  TransitionType,
  UseThemeResult,
} from 'react-native-theme-transition'

The library also exports two runtime values:

import { TRANSITION_META, TRANSITION_TYPES } from 'react-native-theme-transition'

TRANSITION_TYPES is a readonly array of every TransitionType. Use it to build a transition picker, or to validate user input without hardcoding the list.

TRANSITION_META is the per-transition metadata table that drives the type union. Use it to build option pickers that adapt to the selected transition: show an "Inverted" toggle only when the transition supports it, an origin picker only when it grows from a point, and so on.

const meta = TRANSITION_META[transition]
// meta.kind            : 'fade' | 'reveal' | 'shape' | 'shader' | 'strip'
// meta.needsOrigin     : whether the transition reads an `origin` field
// meta.invertible      : whether the transition accepts `inverted: true`
// meta.capturesNew     : whether the engine takes a second snapshot after the swap
// meta.defaultDuration : milliseconds used when no `duration` is set
TransitionkindneedsOrigininvertiblecapturesNewdefaultDuration
fade'fade'350
circularReveal'reveal'350
wipe'strip'350
slide'strip'350
split'strip'350
heart'shape'800
star'shape'800
pixelize'shader'750
dissolve'shader'750

ColorScheme

type ColorScheme = 'light' | 'dark'

Binary OS color scheme. Used by theme.scheme, SystemThemeMap, and internal helpers. Never 'unspecified'. The library normalizes unspecified to 'light'.

ThemeDefinition

type ThemeDefinition = Record<string, string>

A flat record where keys are token names and values are React Native color strings (hex, rgb, rgba, named colors). Every theme in a configuration must declare the same set of keys.

ThemeNames

type ThemeNames<T extends Record<string, ThemeDefinition>> = keyof T & string

Union of theme name strings from your theme map.

TokenNames

type TokenNames<T extends Record<string, ThemeDefinition>> = keyof T[ThemeNames<T>] & string

Union of token name strings shared across every theme in T.

SystemThemeMap

type SystemThemeMap<Names extends string> = Record<ColorScheme, Names>

Maps OS color schemes to theme names. Both light and dark keys are required. Only needed when your themes are not literally named 'light' and 'dark'. See createThemeTransition.

ThemeTransitionConfig

Configuration for createThemeTransition. The full table lives at Create theme transition / Arguments.

FieldTypeDescription
themesTAll themes keyed by name.
animatedbooleanDefault animation on or off. Defaults to true.
transitionTransitionTypeDefault transition kind. Defaults to 'fade'.
darkThemesNames[]Themes that register as a dark color scheme with the OS.
systemThemeMapSystemThemeMap<Names>Maps OS appearance to your theme names.
onTransitionStart(name) => voidAnimated transition begins.
onTransitionEnd(name) => voidAnimated transition completes.
onThemeChange(name) => voidAny theme change.

duration lives only on the per-call SetThemeOptions. There is no config-level duration. Each transition kind has its own calibrated default.

ThemeTransitionAPI

Return type of createThemeTransition. Contains ThemeTransitionProvider and useTheme.

interface ThemeTransitionAPI<T> {
  ThemeTransitionProvider: (props: {
    children: React.ReactNode
    initialTheme: ThemeNames<T> | 'system'
  }) => React.ReactNode
  useTheme: () => UseThemeResult<TokenNames<T>, ThemeNames<T>>
}

UseThemeResult

The return type of useTheme(). Two orthogonal concepts split into four fields.

FieldTypeDescription
theme.nameNamesThe theme currently painted on screen. Always concrete. Never 'system'.
theme.colorsRecord<Tokens, string>Resolved color tokens for the painted theme.
theme.schemeColorSchemeBinary classification, derived from darkThemes.
preferenceNames | 'system'The theme the user explicitly picked.
isTransitioningbooleanTransition overlay is visible.
setTheme(name, opts?) => 'accepted' | 'ignored'Change the preference.

The split is deliberate. theme is what's painted right now (use it for rendering, toggles, asset lookups); preference is what the user picked (use it for picker highlights and persistence). See the theme vs preference decision table.

SetThemeOptions

Discriminated union on transition. The fields available depend on which transition you pick. TypeScript only accepts combinations valid for that variant.

Common Fields

Every variant accepts these:

FieldTypeDefaultDescription
animatedbooleantrueOverride the config-level animation flag.
durationnumberper-kind default (see below)Override the per-kind default duration in milliseconds. Must be >= 0 and finite; throws on NaN, Infinity, or negative values.
easing(t: number) => numberEasing.out(Easing.cubic)Reanimated easing function.
onTransitionStart(name) => voidPer-call start callback. Fires after config.onTransitionStart.
onTransitionEnd(name) => voidPer-call end callback. Fires after config.onTransitionEnd.

Variant-Specific Fields

When transition isFieldTypeDefaultDescription
'circularReveal', 'heart', 'star'originOriginSpecscreen centerPoint or ref where the shape grows from.
'circularReveal', 'heart', 'star'invertedbooleanfalseWhen true, the old theme shrinks into the origin instead of the new theme growing out of it.
'wipe', 'slide'direction'left' | 'right' | 'up' | 'down''right'Cardinal direction the motion is heading.
'split'mode'left-right' | 'top-bottom''left-right'How the screen is divided.
'split'invertedbooleanfalsefalse parts outward, true closes inward like shutters.
'pixelize'blockSizenumber52Maximum pixel block size in points at the midpoint. Must be a finite number >= 2; throws otherwise.
'dissolve'noiseSizenumber5Noise cell size in points. Must be a finite number >= 1; throws otherwise.

Default Durations

When duration is omitted, each transition uses its calibrated default:

TransitionDefault
fade, circularReveal, wipe, slide, split350 ms
heart, star800 ms
pixelize, dissolve750 ms

The same values are exposed at runtime via TRANSITION_META[transition].defaultDuration.

Direction Semantics

direction has the same meaning on wipe and slide. It names the direction the motion is heading. So direction: 'right' means the new theme enters from the LEFT edge and moves rightward.

The library does not auto-flip direction for RTL layouts. The value is absolute, not relative to reading order. If you want the sweep to follow the reading direction in an RTL locale, flip it yourself based on I18nManager.isRTL:

import { I18nManager } from 'react-native'

const direction = I18nManager.isRTL ? 'left' : 'right'
setTheme('dark', { transition: 'wipe', direction })

Examples

// Default fade.
setTheme('dark')

// Wipe right (new theme enters from left).
setTheme('dark', { transition: 'wipe', direction: 'right', duration: 500 })

// Circular reveal, old theme shrinks inward.
setTheme('dark', { transition: 'circularReveal', origin: btnRef, inverted: true })

// Split closing inward like shutters.
setTheme('dark', { transition: 'split', mode: 'top-bottom', inverted: true })

// Pixelize with a custom block size.
setTheme('dark', { transition: 'pixelize', blockSize: 32 })

OriginSpec

type OriginSpec = TransitionOrigin | React.RefObject<View | null>

Either an explicit point or a ref whose center is measured at call time. A ref that has unmounted or returns no coordinates falls back to the center of the screen.

TransitionOrigin

interface TransitionOrigin {
  x: number
  y: number
}

Explicit origin point in React Native density-independent points, relative to the provider's root view. Both x and y must be finite numbers; the engine throws on NaN or Infinity to prevent silent geometry corruption inside the overlay's bounding-radius math.

TransitionType

type TransitionType =
  | 'fade'
  | 'circularReveal'
  | 'heart' | 'star'
  | 'wipe' | 'slide' | 'split'
  | 'pixelize' | 'dissolve'

Derived from the internal TRANSITION_META table. Adding a new transition in source updates both this type union and the runtime TRANSITION_TYPES array.

Type Inference Example

You never need to write generic types by hand. TypeScript infers theme names and token keys from config.themes, then propagates them to useTheme and setTheme.

const light = { bg: '#fff', text: '#000' }
const dark  = { bg: '#000', text: '#fff' }

const { useTheme } = createThemeTransition({ themes: { light, dark } })

const { theme, preference, setTheme } = useTheme()

theme.colors.bg     // type: string, autocomplete: 'bg' | 'text'
theme.colors.foo    // TypeScript error
theme.name          // type: 'light' | 'dark' (always concrete)
theme.scheme        // type: 'light' | 'dark'
preference          // type: 'light' | 'dark' | 'system'
setTheme('dark')    // ok, returns 'accepted' | 'ignored'
setTheme('ocean')   // TypeScript error
setTheme('system')  // always valid

Preserving Inference Across Files

If you split your themes into a separate file or want to type-annotate the themes map, use the satisfies operator instead of a plain type annotation. A direct annotation widens the type back to Record<string, ThemeDefinition> and you lose the literal inference of theme names and token keys.

import { createThemeTransition, type ThemeDefinition } from 'react-native-theme-transition'

// Wrong - widens to Record<string, ThemeDefinition>, useTheme loses narrowing.
const themes: Record<string, ThemeDefinition> = { light, dark }

// Right - keeps the literal type, useTheme narrows to 'light' | 'dark'.
const themes = { light, dark } satisfies Record<string, ThemeDefinition>

createThemeTransition({ themes })

This is a general TypeScript footgun, not specific to this library: satisfies validates the value against a type without widening, while : widens to the annotation. When in doubt, omit the annotation entirely - TypeScript infers the most specific type from the literal.

When to Import Each Type

BuildingImport
A component that consumes theme colorsUseThemeResult (usually inferred)
A bridge to a state managerThemeNames
A wrapper that forwards setTheme optionsSetThemeOptions
A typed config object you split into a separate fileThemeTransitionConfig
Custom system theme mappingSystemThemeMap
Custom transition originOriginSpec, TransitionOrigin
Enumerating transition stylesTransitionType, TRANSITION_TYPES
Building an option picker that adapts per transitionTRANSITION_META

See Also

On this page