Tailwind CSS v4 for React Native — compiled at build time, zero runtime parsing.
Quickstart · Demo · Docs · Architecture
<View className="flex-1 p-4 bg-bg md:flex-row md:gap-4">
<Text className="text-lg text-fg font-semibold dark:text-white">Hello</Text>
</View>A Metro babel transformer compiles every className at build time into a hoisted atom array (['flex-1', 'p-4', 'bg-bg', …]). At runtime, lookupCss walks the array once per hoist and caches the resolved style-object array in a WeakMap — same render → same array reference, so React Native's style diff short-circuits and no native-view update fires unless atoms actually changed.
No runtime Tailwind parser. No regex on the hot path. No
var(--…)left unresolved. Theme tokens, scheme variants, and breakpoint thresholds are all baked into the generated*.style.jsfiles at build time.
![]() |
![]() |
![]() |
![]() |
| Schemes palette + utilities |
Runtime switch light · dark · brand |
Animations enter / loop / repeat |
Interactive active: / focus: + haptics |
From the examples/expo-go demo app — every screen is a real rnwind component.
- 🎨 Real Tailwind v4 —
@tailwindcss/oxide, every utility, every variant - 🌓 Any number of color schemes —
@variantblocks → typedSchemeunion - 📱 Responsive design —
sm:md:lg:xl:2xl:+ your own breakpoints - ✨ Reanimated v4 animations —
enter-*exit-*loop-*repeat-* - 🛡️ Safe-area utilities —
*-saferesolved at render against live insets - ⚡ Zero-parse runtime —
WeakMapcache, stable array refs, no JS-thread cost - 🧪 Real E2E tests —
rnwind/testingon@testing-library/react-native
bun add rnwind tailwindcss// metro.config.js
const { getDefaultConfig } = require('expo/metro-config')
const { withRnwindConfig } = require('rnwind/metro')
module.exports = withRnwindConfig(getDefaultConfig(__dirname), {
cssEntryFile: './global.css',
})/* global.css */
@import 'tailwindcss';
@import 'rnwind/css';
@custom-variant light (&:where(.scheme-light, .scheme-light *));
@custom-variant dark (&:where(.scheme-dark, .scheme-dark *));
@theme {
--color-bg: #f8fafc;
--color-fg: #0f172a;
}
@layer theme {
:root {
@variant dark { --color-bg: #0b1120; --color-fg: #f8fafc; }
}
}// app/_layout.tsx
import { RnwindProvider } from 'rnwind'
import { useColorScheme } from 'react-native'
import { useSafeAreaInsets } from 'react-native-safe-area-context'
export default function Root({ children }) {
const system = useColorScheme()
const insets = useSafeAreaInsets()
return (
<RnwindProvider scheme={system === 'dark' ? 'dark' : 'light'} insets={insets}>
{children}
</RnwindProvider>
)
}// any component
<View className="flex-1 p-4 bg-bg md:flex-row">
<Text className="text-fg dark:text-white">Hello</Text>
</View>import { useRnwind } from 'rnwind'
function StatusBar() {
const { scheme, activeBreakpoint, windowWidth, insets } = useRnwind()
return (
<Text className="text-xs text-muted">
{scheme} · {activeBreakpoint} · {windowWidth}px · top inset {insets.top}
</Text>
)
}useRnwind() is the single context read — destructure what you need (scheme, activeBreakpoint, windowWidth, fontScale, insets, tables, onHaptics). Every value is reactive.
That's it. Detailed setup & options: docs/setup.md.
A fully-featured Expo example lives in examples/expo-go. It exercises every feature: schemes, responsive, animations, safe-area, interactive variants, haptics.
# from repo root
bun install
bun run build
cd examples/expo-go
bun install
bun run ios # or: bun run android / bun run webFirst run takes ~30s while Tailwind oxide scans + the cache materialises. Subsequent saves Fast-Refresh in <100ms.
The example covers four screens:
app/index.tsx— utilities, schemes, responsive, safe-areaapp/animations.tsx—enter-*/loop-*/repeat-*app/interact.tsx—active:/focus:+ hapticsapp/transitions.tsx—layout-*shared transitions
Useful debug scripts:
bun run dump:index # see what the transformer emits for app/index.tsx
bun run inspect # build a dev bundle to .bundle-inspect/
bun run build:ios # production export to .prod-bundle/What it commits to:
- Real Tailwind v4 — every utility, variant, and
@utilityfrom@tailwindcss/oxide. No DSL drift, no subset. - Build-time only. Production bundles ship zero Tailwind code. The runtime is ~3KB of
WeakMaplookups. - Reanimated v4 CSS animations out of the box.
enter-*/exit-*/loop-*/repeat-*compile straight to keyframes Reanimated runs on the UI thread. - Any number of color schemes (
@variant brand,@variant high-contrast, …), not just light/dark. Scheme names flow into TS as a literal union. - Mobile-first responsive with full Tailwind defaults (
sm/md/lg/xl/2xl) +--breakpoint-*overrides. Reactive viauseWindowDimensions().width. - First-class testing.
rnwind/testingruns the real transformer + runtime in your test process, on@testing-library/react-native.
Other RN-Tailwind libraries have their own strengths — try them, pick what fits your app. rnwind's bet is on a strict build-time pipeline + a tiny stable runtime.
docs/responsive.md |
sm: / md: / lg:, custom breakpoints, activeBreakpoint |
docs/schemes.md |
@variant blocks, runtime switch, typed Scheme |
docs/animations.md |
enter-*, exit-*, loop-*, repeat-*, custom @keyframes |
docs/safe-area.md |
*-safe, *-safe-or-N, h-screen-safe, provider wiring |
docs/interact.md |
active: / focus: variants, chainPress, haptics |
docs/api.md |
Full API reference — hooks, components, low-level |
docs/testing.md |
renderWithCss, renderHookWithCss, Bun + Jest setup |
docs/setup.md |
Metro options, monorepos, IntelliSense, .d.ts generation |
docs/architecture.md |
Full pipeline — parser, builder, runtime, transformer |
- No runtime Tailwind. Your production bundle does not ship
@tailwindcss/oxide,lightningcss, ortailwindcss. - No CSS cascade. Every className resolves to a flat
{ property: value }map at compile time; precedence is class-list order (last wins on RN flatten). - No
var()at runtime. Theme variables resolve during compile, per scheme. - No selector combinators.
&:hover > *doesn't map to RN.active:/focus:work via matching RN props;sm:/md:/ etc. work via window-width gating.
bun install
bun run build # rollup → packages/rnwind/lib
bun run test # all packages
bun run code-check # typecheck + lint + test (CI gate)Bun-only. No npm, no tsx.
Quickstart · Demo · Docs · Architecture
MIT · Built with ♥ and Bun



