With NativeWind in place, core components accept className. Each class is one small style, so a component's look is readable where it is used:
<View key={id}
className="flex-row items-center gap-3 rounded-xl bg-surface p-3 shadow">
<Image source={cover(book)} className="h-16 w-11 rounded" />
<View className="flex-1">
<Text className="text-base font-semibold text-ink" numberOfLines={1}>
{book.title}
</Text>
<Text className="text-sm text-ink/60">{qty} x ${book.price.toFixed(2)}</Text>
</View>
<Pressable onPress={() => remove(id)}
className="rounded-full px-3 py-2 active:bg-brand/20">
<Text className="font-semibold text-brand">Remove</Text>
</Pressable>
</View>Tailwind 5,202 's spacing scale is in steps of 4: p-3 is 12 and h-16 is 64, density-independent pixels here rather than CSS pixels. /60 sets opacity on a color, and active: applies while a Pressable is pressed, replacing the ({ pressed }) => ... style function of Touch, Press and Switches. Platform variants such as ios: and android: work too. Text styles still do not inherit from a View, so every Text needs its own color class.
A third-party component gets the same treatment once you register it: cssInterop(ExpoImage, { className: 'style' }) from nativewind maps its className prop onto style. Class names must appear whole in the source: the scanner cannot see bg-${color}.