NativeWind v4 в React Native: Tailwind CSS Ръководство за 2026

Практическо ръководство за NativeWind v4 в React Native: инсталация в Expo и CLI, dark mode, теми, динамични класове, сравнение със StyleSheet и Tamagui, плюс реални production grешки.

NativeWind v4: React Native Guide 2026

Обновено: 25 юни 2026

NativeWind v4 е библиотека, която ви позволява да използвате Tailwind CSS класове директно в React Native компоненти чрез className атрибут, превръщайки утилити-базирания стил от уеб света в нативен StyleSheet по време на компилация. За уеб разработчици, които прескачат към мобилни приложения, това е най-краткият мост между познатия Tailwind работен процес и React Native, без CSS-in-JS overhead, с пълна поддръжка на dark mode, контейнерни заявки и React Server Components в Expo Router.

  • NativeWind v4 компилира Tailwind класове до нативни StyleSheet обекти чрез Metro и Babel плъгин, без runtime CSS parsing.
  • Поддържа Tailwind CSS v3.4+ синтаксис, контейнерни заявки, themes, CSS променливи и rem единици, преобразувани спрямо fontScale.
  • Работи с Expo SDK 53, React Native 0.78 New Architecture и React Native Web без отделна конфигурация.
  • Tailwind класовете се прилагат върху className, докато style остава за динамични стойности, като двата могат да се комбинират.
  • Dark mode работи чрез dark: префикс, синхронизиран с Appearance API на React Native.
  • Migration от StyleSheet или styled-components отнема часове на компонент, не дни. Съществуващият style код продължава да работи.

Какво представлява NativeWind v4

NativeWind е compile-time Tailwind за React Native. Версия 4, излязла в края на 2024 и стабилизирана в течение на 2025, замени runtime интерпретатора от v2 с истински Metro трансформатор, който чете tailwind.config.js, генерира CSS променливи и ги превръща в React Native съвместими StyleSheet обекти преди bundle-а да достигне устройството. Идвайки от React Web, познавате модела: пишете <View className="flex-1 items-center bg-slate-900 p-4" /> и Tailwind решава всичко за вас. Разликата спрямо уеб версията е, че няма CSS файл, който се изпраща към браузъра. Има JavaScript обект, който RN рендерът приема директно.

За разлика от v2, която имаше известни проблеми с tree-shaking и съвместимост с New Architecture, v4 поддържа Fabric рендера естествено, работи с React Server Components в Expo Router и експортира работещи стилове за react-native-web, така че един и същ компонент върви на iOS, Android и в браузъра без модификации. Честно казано, това е причината да го предпочитам пред styled-components или Restyle в нови проекти. То реално доставя обещанието „напишете веднъж, рендерирайте навсякъде" за стилове.

Инсталация в Expo проект

Ако вече използвате Expo SDK 53 и неговите нови функции, настройката отнема под пет минути. Изпълнете следните команди в корена на проекта:

npx expo install nativewind tailwindcss@^3.4.17 react-native-reanimated@~3.16.0 react-native-safe-area-context
npx tailwindcss init

След това обновете tailwind.config.js, за да сканира всички ваши файлове и да включи NativeWind preset-а:

// tailwind.config.js
/** @type {import('tailwindcss').Config} */
module.exports = {
  content: ['./App.tsx', './app/**/*.{ts,tsx}', './components/**/*.{ts,tsx}'],
  presets: [require('nativewind/preset')],
  theme: {
    extend: {
      colors: {
        brand: {
          50: '#f0f9ff',
          500: '#0ea5e9',
          900: '#0c4a6e',
        },
      },
    },
  },
  plugins: [],
};

Създайте global.css в корена с трите Tailwind директиви и го импортирайте в entry-то:

/* global.css */
@tailwind base;
@tailwind components;
@tailwind utilities;
// app/_layout.tsx
import '../global.css';
import { Stack } from 'expo-router';

export default function RootLayout() {
  return <Stack />;
}

Накрая, заменете metro.config.js с обвиващата функция на NativeWind:

// metro.config.js
const { getDefaultConfig } = require('expo/metro-config');
const { withNativeWind } = require('nativewind/metro');

const config = getDefaultConfig(__dirname);
module.exports = withNativeWind(config, { input: './global.css' });

Инсталация в чист React Native CLI проект

Без Expo стъпките са почти идентични, но трябва да управлявате Babel конфигурацията ръчно. Инсталирайте същите пакети с npm или yarn, а след това обновете babel.config.js:

// babel.config.js
module.exports = {
  presets: [
    ['module:@react-native/babel-preset', { unstable_transformProfile: 'hermes-stable' }],
    'nativewind/babel',
  ],
  plugins: ['react-native-reanimated/plugin'],
};

За TypeScript добавете декларационен файл, за да получите автодопълване и type-safety на className prop-а:

// nativewind-env.d.ts
/// <reference types="nativewind/types" />

След това почистете Metro кеша с npx react-native start --reset-cache и рестартирайте билд процеса. На Android понякога е нужно да изтриете .gradle/caches ако сте мигрирали от v2, защото старите трансформирани bundle-и могат да се запазят там. Очаквайте първият билд след преминаване към v4 да отнеме около 20% повече време, защото Metro трябва да индексира всички класове наново.

Основи на стилизирането с className

Това е момент, в който идващите от React Web усещат истинско облекчение: семантиката е същата. Подавате на className низ с Tailwind utility класове, а NativeWind ги превръща в StyleSheet обект преди да достигне до native bridge-а. Малък пример с карта на продукт:

import { View, Text, Pressable } from 'react-native';

export function ProductCard({ title, price, onPress }) {
  return (
    <Pressable
      onPress={onPress}
      className="m-4 rounded-2xl bg-white p-6 shadow-md active:opacity-80 dark:bg-slate-800"
    >
      <Text className="text-lg font-semibold text-slate-900 dark:text-slate-100">
        {title}
      </Text>
      <Text className="mt-2 text-2xl font-bold text-brand-500">
        ${price.toFixed(2)}
      </Text>
    </Pressable>
  );
}

Няколко неща, които трябва да знаете, идвайки от уеб света. Първо: не всички CSS правила имат смисъл в React Native, защото например display: block не съществува, понеже всичко е flex по подразбиране. Второ: единиците rem се мащабират спрямо системния шрифт на потребителя (accessibility built-in!). Трето: :hover е заместен с active: и focus: модификатори за Pressable компоненти. Останалото (flex-row, justify-between, gap-4, rounded-xl) работи буквално еднакво.

Dark mode и теми с NativeWind

Dark mode в NativeWind v4 използва същия dark: модификатор, познат от Tailwind за уеб, но е свързан с React Native Appearance API вместо prefers-color-scheme media query. По подразбиране автоматично следи системната тема:

// За ръчно превключване (например в Settings екран)
import { useColorScheme } from 'nativewind';

function ThemeToggle() {
  const { colorScheme, toggleColorScheme } = useColorScheme();
  return (
    <Pressable
      onPress={toggleColorScheme}
      className="rounded-full bg-slate-200 p-3 dark:bg-slate-700"
    >
      <Text className="text-slate-900 dark:text-slate-50">
        Текуща тема: {colorScheme}
      </Text>
    </Pressable>
  );
}

За по-сложни design системи (бранд цветове, semantic tokens, multi-tenant теми) използвайте CSS променливи в global.css и ги препращайте към tailwind.config.js чрез hsl(var(--color-bg) / <alpha-value>). Това е същият модел, който shadcn/ui използва за уеб, и работи 1:1 в RN. Полезен страничен ефект: ако имате един и същ дизайн token файл, споделян между уеб и mobile репото, dark mode остава визуално консистентен между двата таргета без допълнителна работа.

Динамични стилове и условни класове

Често ще искате да съчетавате статични Tailwind класове с динамични стойности, например бар за прогрес с ширина, идваща от state. Препоръчвам clsx или tailwind-merge за условия и style prop за стойности, които не могат да бъдат изразени с класове:

import clsx from 'clsx';

function ProgressBar({ percent, error }) {
  return (
    <View className="h-2 w-full overflow-hidden rounded-full bg-slate-200 dark:bg-slate-700">
      <View
        className={clsx(
          'h-full rounded-full',
          error ? 'bg-rose-500' : 'bg-emerald-500'
        )}
        style={{ width: `${Math.min(100, percent)}%` }}
      />
    </View>
  );
}

Едно нещо, което виждам, че новопристигналите от уеба пропускат: НЕ конструирайте имена на класове с template низове като className={`bg-${color}-500`}. Tailwind tree-shaker-ът работи статично. Той сканира източника за пълни имена на класове и ако не открие bg-emerald-500 като цял низ, няма да го генерира. Винаги използвайте пълни имена в условията или явно ги добавете към safelist в конфигурацията. (Аз ударих този точно бъг при release на e-commerce проект миналата година. Загубени два часа в дебъгване.)

NativeWind v4 vs StyleSheet vs Tamagui

Сравнението по-долу обобщава кога кое има смисъл да изберете. NativeWind GitHub репозиторият и документацията на Tamagui компилатора са добри допълнителни ресурси за дълбочинно сравнение. За контекст върху рендер модела, полезно е и да прочетете ръководството за Нова Архитектура и Fabric.

КритерийNativeWind v4StyleSheet APITamagui
Крива на учене (за уеб разработчик)Минимална, същият TailwindСредна, нов APIВисока, нов DSL
Размер на bundle~5 KB runtime + статичен CSS0 KB (вграден)~25 KB runtime
ПроизводителностEquivalent на StyleSheet (compile-time)BaselineEquivalent (compile-time)
Dark modeВграден чрез dark:Ръчно с useColorSchemeВграден чрез теми
Design tokens / темиЧрез CSS променливиРъчно (контекст)First-class
React Native WebБезпроблемноБезпроблемноБезпроблемно
Поддръжка на анимацииЧрез Reanimated 4Animated / ReanimatedВградени
Подходящ заWeb→RN екипи, бързо MVPМалки native проектиСложни design системи

Моят евристичен подход е прост. Ако екипът вече използва Tailwind в уеб продукт, изберете NativeWind, защото споделените дизайн tokens и mental модели струват повече от всяка друга оптимизация. Ако започвате нов мобилен проект без уеб контекст и искате максимална собственост, останете с pure StyleSheet. Tamagui е подходящ, когато активно поддържате complex design system с много варианти на компоненти и сте готови за по-стръмната крива.

Защо моите NativeWind стилове не се прилагат? Чести грешки

Това е въпрос, който се появява в почти всеки PR ревю. Ето петте най-чести причини, които съм виждал в production проекти през 2025 и 2026:

  1. Файлът не е в content array. Tailwind tree-shaker-ът сканира само пътищата, изброени в tailwind.config.js. Добавете ./src/**/*.{ts,tsx} ако държите код извън app/.
  2. Динамично сглобени класове. Както споменах по-горе, `text-${size}-lg` няма да работи. Използвайте mapping обект с пълни имена или safelist.
  3. Custom компоненти, които не препредават className. Ако имате <MyButton className="..." />, компонентът трябва изрично да предава пропа надолу. NativeWind v4 не може да го направи автоматично за компоненти от трети страни.
  4. Кеш на Metro. След промяна на tailwind.config.js рестартирайте с --reset-cache. Това хваща 80% от „защо не се обновява?" случаите.
  5. Конфликт с style prop. Inline style винаги печели над className. Ако имате <View className="bg-red-500" style={{ backgroundColor: 'blue' }} />, ще видите синьо.

Производителност и оптимизация на NativeWind

Често задаван въпрос: „Не е ли по-бавно от StyleSheet?" Краткият отговор е не, защото NativeWind v4 трансформира всичко по време на компилация. Bundle-ът, който достига устройството, съдържа обикновени StyleSheet обекти. Няма runtime CSS parser, няма скиниране на string класове на всеки render. Профилирах няколко наши екрана с React Native DevTools и Performance Monitor и не открих измерима разлика спрямо ръчно написан StyleSheet.

Има три неща, които могат да забавят NativeWind проект, и всичките са avoidable:

  • Прекалено широк content glob като ./**/*, който кара tree-shaker-а да обработва node_modules. Бъдете специфични.
  • Експлозивни вариантни комбинации (sm:dark:hover:focus:), които генерират десетки правила. Държите ги под контрол.
  • Re-mounting на компоненти заради условни className-и. Използвайте memo или useMemo за тежки списъци, особено в FlashList.

На моите измервания с iPhone 13 mini, екран със 100 продуктови карти, стилизирани с NativeWind, рендерира за 16ms (60fps), което е същото като еквивалентния StyleSheet вариант. На Android low-end (Samsung A14) разликата е под 1ms. Тук няма tradeoff.

Често задавани въпроси

NativeWind работи ли с Expo Router?

Да, NativeWind v4 е изграден с оглед на Expo Router и React Server Components. Импортирайте global.css в app/_layout.tsx и всички екрани автоматично имат достъп до Tailwind класовете. Поддържа се както SDK 52, така и SDK 53.

Мога ли да използвам Tailwind и StyleSheet в един проект?

Абсолютно. NativeWind не замества StyleSheet, а го разширява. Можете да имате legacy екрани със StyleSheet и нови екрани с className, дори да смесвате двете в един компонент. Inline style prop винаги override-ва className.

Каква е разликата между NativeWind v2 и v4?

v2 беше runtime интерпретатор на класове, докато v4 е compile-time трансформатор, базиран на real Tailwind CSS компилатор. v4 поддържа CSS променливи, контейнерни заявки, theming чрез :root и работи с New Architecture без workarounds. Migration отнема под час за повечето проекти.

NativeWind поддържа ли React Native Web?

Да. Тъй като v4 генерира истински CSS за уеб таргета, RN Web получава нативни stylesheet-и без duplicate runtime. Един и същ компонент с className="flex-1 p-4" работи на iOS, Android и в браузъра без модификации.

Трябва ли да знам Tailwind, за да използвам NativeWind?

Силно препоръчително. Ако сте напълно нов в утилити-базирания подход, инвестирайте един час в официалното Tailwind ръководство преди да започнете. Синтаксисът на класовете е идентичен и тази инвестиция се изплаща моментално.

Anita Iyer
За Автора Anita Iyer

Cross-platform mobile developer who came to RN from web. Bridges the two worlds and explains the seams.