Back to Blog

NativeWind is not Tailwind, and the gap is the runtime

React NativeNativeWindTailwindMobile DevelopmentCSS

The first NativeWind bug everyone hits is silent. You write <View className="text-blue-500">, the text stays black, nothing errors, and you lose twenty minutes. You spent a year of Tailwind learning that utility classes compose and cascade anywhere. NativeWind looks identical and does not work that way.

NativeWind is not Tailwind for native. It is React Native's StyleSheet with Tailwind's class names bolted on, and the places where that abstraction leaks are the whole story.

Once you stop expecting web semantics, it becomes the styling option I reach for in React Native. But you have to learn what it actually is first.

Text styles do not cascade, because there is no DOM

On the web, text-blue-500 on a parent sets a color that children inherit, because CSS cascades through the DOM. React Native has no DOM and no inheritance. A <Text> does not read styles off its parent <View>. So the Tailwind reflex of styling a container and letting text come along is exactly the bug:

// Does nothing useful: View has no text to color
<View className="text-blue-500">
  <Text>Hello</Text>
</View>

// Correct: style the Text directly
<View className="bg-blue-500">
  <Text className="text-white">Hello</Text>
</View>

This is not a NativeWind quirk. It is React Native's model showing through a Tailwind-shaped hole.

NativeWind drops half of CSS, and that's the right call

NativeWind does not support most of CSS, because React Native's layout engine does not. No CSS Grid. No :nth-child or most pseudo-classes. No CSS keyframe animations (you reach for the Animated API or Reanimated). It is tempting to read that as NativeWind being unfinished. It is not. React Native's box model is Flexbox-only and platform-native, and a styling layer that faithfully exposed all of CSS would be lying to you about what the platform can render. The smaller surface is honest.

Practically: lay out with Flexbox, because that is all there is.

<View className="flex-row items-center justify-between gap-4">
  <View className="flex-1"><Text>Left</Text></View>
  <View className="flex-1"><Text>Right</Text></View>
</View>

And since there is no Grid, multi-column is FlatList with numColumns, not grid-cols-2:

<FlatList
  data={items}
  numColumns={2}
  contentContainerClassName="p-4 gap-4"
  renderItem={({ item }) => (
    <View className="flex-1 aspect-square"><Text>{item.title}</Text></View>
  )}
/>

The real difference is that it runs at runtime

Here is the one that matters under load. Tailwind on the web compiles to a static CSS file at build time, and the browser does the rest. NativeWind parses your class strings and builds React Native StyleSheet objects at runtime, on device. Same authoring experience, completely different execution model.

That is not a reason to avoid it. It is the thing to respect. Keep class strings reasonable, do not rebuild giant className expressions on every render in a hot list, and memoize components whose styles never change. The mechanism tells you where the cost is. You do not need a benchmark to know that runtime style construction in a fast-scrolling FlatList row is the place to be careful.

The parts that are genuinely better than raw StyleSheet

Once you accept what it is, NativeWind earns its place by making the annoying parts of React Native styling terse. Press states, since there are no hover states on a touchscreen:

<Pressable className="bg-blue-500 active:bg-blue-700">
  <Text className="text-white">Press me</Text>
</Pressable>

Platform and theme variants inline, instead of Platform.select and useColorScheme plumbing:

<View className="ios:pt-12 android:pt-4 bg-white dark:bg-gray-800">
  <Text className="text-black dark:text-white">Adapts to platform and theme</Text>
</View>

And the shadow split that every React Native dev gets wrong once, handled by name: iOS reads shadow-*, Android needs elevation. NativeWind lets you say both in one place instead of branching by hand.

So: use it, but stop expecting Tailwind

I use NativeWind. It collapses the most tedious parts of React Native styling into something close to muscle memory, and a shared vocabulary with the web team is real value. But the developers who fight it are the ones who expect web Tailwind semantics and treat every difference as a bug. The ones who like it learned React Native's layout model first, then picked up NativeWind to type it faster.

Learn the platform, then add the shorthand. Not the other way around.