Light and dark, switched inside the shadow tree. Zero re-renders.

drag across to move the shade
React Native 0.86 · Fabric · Nitro

Mounts within 1.09× of StyleSheet. Switches themes in 2.45 ms.

New ArchitectureiOS & AndroidUniwind 1.12 / 1.13MITexperimental 0.x
npm install shadewind react-native-nitro-modules@^0.37.1
0re-renders on a theme switch for views it paints
2.45msiOS theme switch, 2003 views
0.14msAndroid theme switch, 2003 views
1.09×of StyleSheet mount time, with precompile (iOS)
Same screen, two engines

Watch who has to re-render.

Both phones run the same Account screen. On the left, every styled component renders again, and each one flashes as it does. On the right, shadewind writes the new props in one native commit, so nothing flashes and the JS thread stays flat.

Runtime themingevery component re-renders
JS thread0 renders
setTheme('dark') tap to switch · illustration, not a measurement
shadewindone native commit, zero re-renders
1 native commit
JS thread0 renders
Quick start

Up and running in three files.

Your existing classNames don't change. Pick your setup, then walk the steps.

    terminal
    How it works

    Props per theme, written in at commit time.

    Shadewind remembers each view's props for every theme and rewrites them inside React Native's own shadow tree commit.

    JS

    setTheme('dark')

    C++

    A native commit hook picks it up

    Shadow tree

    Each bound view's dark props are written in

    Fabric

    Mounted in the same commit

    Animated switch, optional

    setTheme('dark', { transition: { type: 'fade', durationMs: 250 } }) cross-fades. Instant by default.

    Precompile, optional

    precompileClassNames: true turns classNames on View and Text into hookless components to cut mount cost.

    See what it binds

    A dev-only diagnostics log lists every view it binds and every commit it themes.

    Tested natively

    A harness runs React Native's real C++ renderer, so commit logic is checked without a device.

    Honest fallbacks

    Inline backgrounds over a className colour and active: states re-render, as in plain Uniwind.

    Bounded memory

    Since 0.3.2 the style cache is bounded, so thousands of new classNames don't grow the process.

    Benchmark · 2003 views · Release builds

    Against plain StyleSheet, the floor.

    StyleSheet is React Native with no styling library, the fastest anything can mount. Time is measured until the JS thread is idle, ten runs each. These are simulator and emulator numbers; nothing has been measured on a physical device yet.

    t = 0.0 ms slowed 60×

    Full protocol, spreads and what didn't help: docs/BENCHMARK.md

    Status & docs

    Experimental, and upfront about it.

    0.x · New Architecture only

    React Native 0.86. iOS is the primary target; Android has one emulator of testing so far. Verified with Uniwind 1.12.x, and 1.13.x without the native class resolver. Other versions run as plain Uniwind.

    From the author

    Vibe-coded with Claude Code by a dev who loves programming. Take the code and numbers with a grain of salt, and kindly roast where it's wrong.