NativeWind v4 สำหรับ React Native 2026: Tailwind CSS, Dark Mode และ Responsive UI

คู่มือใช้งาน NativeWind v4 กับ React Native และ Expo SDK 52+ ครอบคลุมติดตั้ง Metro/Babel, Dark Mode, Responsive, CSS Variables, Container Queries และ Animation ด้วย Reanimated 4 พร้อมเปรียบเทียบกับ StyleSheet และ styled-components พร้อมโค้ดตัวอย่างปี 2026

NativeWind v4 คู่มือ React Native 2026

อัปเดต: 12 สิงหาคม 2026

NativeWind v4 คือ library ที่นำ Tailwind CSS มาใช้กับ React Native โดยคอมไพล์คลาส utility เป็น StyleSheet.create ที่ React Native เข้าใจโดยตรง ไม่ใช่ inline style ประสิทธิภาพจึงเทียบเท่าเขียน StyleSheet ด้วยมือ ในเวอร์ชัน v4 (เริ่มปล่อยตัวเสถียรปลายปี 2024 และปรับปรุงต่อเนื่องถึงปี 2026) ทีมงานเขียนใหม่ทั้งหมดด้วย LightningCSS parser จึงรองรับ CSS Variables, Media Queries, Container Queries, @apply และเข้ากับ New Architecture (Fabric + TurboModules) ได้อย่างสมบูรณ์ ตอนนี้ผมใช้กับ Expo SDK 52 มาสามโปรเจกต์แล้ว และแนะนำเป็นตัวเลือกแรกสำหรับทีมที่มี background เว็บอยู่แล้ว

  • NativeWind v4 คอมไพล์ Tailwind CSS เป็น StyleSheet ของ React Native ผ่าน Metro + Babel plugin ไม่ใช่แค่แปลง className เป็น inline style
  • รองรับ CSS Variables, prefers-color-scheme, Media Queries และ Container Queries โดยไม่ต้องเขียนโค้ด JavaScript เพิ่ม
  • ทำงานร่วมกับ Expo SDK 52+, React Native 0.79 และ New Architecture ได้เต็ม 100% รวมถึง React Native Web แบบ isomorphic
  • Dark Mode ตั้งค่าครั้งเดียวใน tailwind.config.js โดยใช้ darkMode: "media" หรือ "class" พร้อม hook useColorScheme
  • เร็วกว่า styled-components ประมาณ 30-40% ในการ mount ครั้งแรก เพราะไม่ต้องคำนวณ style tree ตอน runtime
  • รองรับการทำ animation ผ่าน react-native-css-interop ที่แปลง transition-* และ keyframes เป็น worklet ของ Reanimated 4

NativeWind v4 คืออะไรและทำงานอย่างไร

NativeWind เป็นระบบ styling แบบ utility-first สำหรับ React Native ที่ยึดหลักไวยากรณ์ของ Tailwind CSS ทุกอย่าง คุณเขียน className="flex-1 items-center bg-slate-900" เหมือนตอนทำเว็บ แต่ output ที่ได้คือ StyleSheet ของ React Native ที่ผ่านการ optimize มาแล้ว ไม่ใช่ inline object ที่ต้อง diff ใหม่ทุก render

สิ่งที่ทำให้ v4 ต่างจากทุกเวอร์ชันก่อน คือทีมงานเลิกเขียน CSS parser เองแล้วหันมาใช้ lightningcss (parser เดียวกับที่ Tailwind CSS v4 ใช้) กระบวนการทำงานคือ Metro bundler จะเรียก plugin ของ NativeWind ที่รัน Tailwind สร้างไฟล์ CSS จริง จากนั้น react-native-css-interop แปลง CSS นั้นเป็น JavaScript object ที่ตรงกับ StyleSheet API ของ RN ทำให้ค่า 1rem = 16 หน่วย, px จะถูกละทิ้ง และ % จะถูกจัดการอย่างถูกต้อง

ในทางสถาปัตยกรรม NativeWind v4 ไม่ได้แทน StyleSheet แต่สร้าง StyleSheet ให้ต่างหาก ดังนั้นคุณสามารถผสม className กับ style ในคอมโพเนนต์เดียวกันได้ และในกรณีที่ต้องการ dynamic style จาก state คุณส่ง className ด้วย template literal ได้ตรง ๆ Metro จะเห็นทุก class ล่วงหน้าเพราะ Tailwind สแกน AST ตั้งแต่ build time

ต่างจาก NativeWind v2/v3 อย่างไร

สำหรับทีมที่มาจาก v2 การอัปเกรดขึ้น v4 คือการเปลี่ยนเครื่องยนต์ทั้งชุด v2 ใช้ tailwindcss-react-native ที่แปลง class เป็น inline style ทำให้ทุกครั้งที่ props เปลี่ยน จะต้อง recompute object ใหม่ ส่วน v3 (เวอร์ชันสั้น ๆ ในปี 2023) เริ่มใช้ Babel plugin แต่ยังไม่รองรับ CSS variables อย่างครบถ้วน

ส่วน v4 คือการรื้อใหม่ทั้งหมด นี่คือฟีเจอร์ที่เพิ่งมี

  • CSS-first API รองรับ @apply, @layer, @media, @container ได้เต็ม syntax
  • CSS Variables จริง โดย var(--color-primary) ถูกจัดการโดย StyleSheet ทำให้เปลี่ยน theme ได้แบบ real-time โดยไม่ต้อง re-render tree
  • Container Queries เขียน @container (min-width: 400px) ได้ใน RN เพื่อ layout ตามขนาด parent ไม่ใช่ตาม screen
  • React Server Components (RSC) ready เตรียมพร้อมสำหรับ Expo Router 4 ที่รองรับ RSC ในโหมด server
  • Fabric compatible ทำงานร่วมกับ คู่มือ React Native New Architecture ได้โดยไม่ต้อง flag พิเศษ

วิธีติดตั้ง NativeWind v4 กับ Expo SDK 52+

คำถามที่ผมได้ยินบ่อยที่สุดคือ "ทำไมของฉันติดตั้งไม่สำเร็จ" เกือบทุกครั้งเป็นเพราะข้าม step หนึ่งใน 5 ขั้นตอนนี้ ผมทดสอบกับ Expo SDK 52 + React Native 0.79 + Node 20 LTS ล่าสุดแล้ว ทำงานได้ทั้ง iOS, Android และ Web (โปรเจกต์จริงหนึ่งตัวก็ deploy พร้อมกันทั้งสามแพลตฟอร์ม)

ขั้นที่ 1 ติดตั้ง dependencies ทั้งชุด

npx create-expo-app@latest my-app --template default
cd my-app

npx expo install nativewind tailwindcss@^3.4.0 react-native-reanimated react-native-safe-area-context

ขั้นที่ 2 สร้างไฟล์ Tailwind config

npx tailwindcss init

ขั้นที่ 3 แก้ tailwind.config.js ให้สแกนทุกไฟล์ที่มี className

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

ขั้นที่ 4 สร้างไฟล์ global.css ที่ root ของโปรเจกต์

@tailwind base;
@tailwind components;
@tailwind utilities;

ขั้นที่ 5 import ไฟล์ CSS ใน entry point (สำคัญมาก ลืมบ่อยที่สุด)

// app/_layout.tsx (Expo Router) หรือ App.tsx
import "../global.css";
import { Stack } from "expo-router";

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

ทีนี้รัน npx expo start --clear ครั้งแรกเพื่อบังคับให้ Metro rebuild cache ถ้าไม่เคลียร์ cache จะเจอ error ประเภท "Unknown class name" แทบทุกครั้ง (ผมเจอ error นี้ในช่วง onboard ทีมใหม่แทบทุกคน)

ตั้งค่า Metro, Babel และ tailwind.config.js

NativeWind v4 ต้องการทั้ง Metro transformer และ Babel plugin ทำงานประสานกัน หลายคนตั้งเพียงตัวเดียวและเจอปัญหาว่า class บางกลุ่มไม่ทำงาน มาดูการตั้งค่าที่สมบูรณ์กัน

ไฟล์ metro.config.js ใช้ helper withNativeWind ห่อ Metro config ของ Expo

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

const config = getDefaultConfig(__dirname);

module.exports = withNativeWind(config, {
  input: "./global.css",
  inlineRem: 16,
});

ไฟล์ babel.config.js เพิ่ม preset ของ NativeWind ต่อจาก babel-preset-expo

module.exports = function (api) {
  api.cache(true);
  return {
    presets: [
      ["babel-preset-expo", { jsxImportSource: "nativewind" }],
      "nativewind/babel",
    ],
    plugins: ["react-native-reanimated/plugin"],
  };
};

ถ้าคุณใช้ TypeScript ให้เพิ่มไฟล์ nativewind-env.d.ts ที่ root เพื่อให้ IDE เห็น type ของ className

/// <reference types="nativewind/types" />

การตั้งค่า Dark Mode

Dark Mode ใน NativeWind v4 ทำได้สองแบบ คือตาม system (แนะนำ) หรือควบคุมด้วย state manually สำหรับผู้ใช้ที่อยากให้แอปเปลี่ยนตาม iOS/Android setting อัตโนมัติ ให้ใช้ darkMode: "media"

// tailwind.config.js
module.exports = {
  darkMode: "media",
  // ...
};

จากนั้นใช้ prefix dark: ในทุก className

import { View, Text } from "react-native";

export default function Card() {
  return (
    <View className="p-4 bg-white dark:bg-slate-900 rounded-xl">
      <Text className="text-slate-900 dark:text-slate-100 text-lg font-semibold">
        สวัสดี NativeWind v4
      </Text>
    </View>
  );
}

สำหรับกรณีที่ต้องการปุ่มสลับ theme เอง ใช้ darkMode: "class" แล้วเรียก colorScheme จาก nativewind

import { colorScheme, useColorScheme } from "nativewind";
import { Pressable, Text } from "react-native";

export function ThemeToggle() {
  const { colorScheme: current } = useColorScheme();

  return (
    <Pressable
      onPress={() => colorScheme.set(current === "dark" ? "light" : "dark")}
      className="px-4 py-2 bg-brand-500 rounded-lg"
    >
      <Text className="text-white font-medium">
        เปลี่ยนเป็น {current === "dark" ? "โหมดสว่าง" : "โหมดมืด"}
      </Text>
    </Pressable>
  );
}

สำหรับการเก็บค่าที่ผู้ใช้เลือกไว้ระหว่าง session ผมแนะนำให้จับคู่กับ MMKV อ่านเพิ่มได้ที่ คู่มือจัดเก็บข้อมูล React Native แบบ local storage เพื่อให้เขียน/อ่านเร็วกว่า AsyncStorage 30 เท่า

Responsive Design และ Breakpoints

Responsive ใน NativeWind v4 ทำงานเหมือน Tailwind บนเว็บทุกประการ breakpoint เริ่มต้นคือ sm (640px), md (768px), lg (1024px), xl (1280px), 2xl (1536px) วัดจากความกว้างของหน้าจอ

<View className="flex-col md:flex-row gap-4 p-4">
  <View className="flex-1 h-32 bg-slate-200 md:h-64" />
  <View className="flex-1 h-32 bg-slate-300 md:h-64" />
</View>

บนมือถือคอลัมน์จะซ้อนกัน (flex-col) พอเปลี่ยนเป็น tablet (≥768px) จะกลายเป็นแนวนอน (flex-row) โดยอัตโนมัติ ไม่ต้องเรียก Dimensions.get() หรือใช้ hook แยก

ในเวอร์ชัน v4 ยังรองรับ container queries ที่ช่วยให้ layout ตอบสนองขนาด parent ไม่ใช่ screen เหมาะกับคอมโพเนนต์ที่ reuse ในหลายบริบท

<View className="@container flex-1">
  <View className="@md:flex-row flex-col gap-2">
    <Text className="@lg:text-2xl text-base">หัวข้อ</Text>
  </View>
</View>

สำหรับการรองรับ RTL (เช่นภาษาอาหรับ) ใช้ logical properties เช่น ms-4 (margin-start) แทน ml-4 เพื่อให้ Layout สลับซ้ายขวาอัตโนมัติเมื่อ user เปลี่ยนภาษา

Custom Colors, CSS Variables และ Theme

วิธีขยาย theme มีสองแนวทาง แนวแรกคือประกาศใน tailwind.config.js ตามปกติ ซึ่งเหมาะกับสีที่ตายตัว แนวที่สองคือใช้ CSS Variables ในไฟล์ global.css ซึ่งเปลี่ยนได้ตอน runtime นี่คือ pattern ที่ผมใช้ในโปรเจกต์ล่าสุด

/* global.css */
@tailwind base;
@tailwind components;
@tailwind utilities;

@layer base {
  :root {
    --color-bg: 255 255 255;
    --color-fg: 15 23 42;
    --color-accent: 14 165 233;
  }
  @media (prefers-color-scheme: dark) {
    :root {
      --color-bg: 15 23 42;
      --color-fg: 226 232 240;
      --color-accent: 56 189 248;
    }
  }
}
// tailwind.config.js
module.exports = {
  theme: {
    extend: {
      colors: {
        bg: "rgb(var(--color-bg) / <alpha-value>)",
        fg: "rgb(var(--color-fg) / <alpha-value>)",
        accent: "rgb(var(--color-accent) / <alpha-value>)",
      },
    },
  },
};

ตอนใช้งานเขียนสั้นมาก className="bg-bg text-fg" จะเปลี่ยนตาม dark mode อัตโนมัติโดยไม่ต้องใส่ prefix dark: ทุกที่ และคุณสามารถส่ง alpha ด้วย text-fg/70 ได้เหมือน Tailwind บนเว็บ

Animations กับ Reanimated 4

NativeWind v4 รองรับ transition-* และ animation utilities ของ Tailwind แบบ native โดย compile เป็น worklet ของ React Native Reanimated 4 พร้อม CSS animations ที่รันบน UI thread ทำให้ไม่กระตุกแม้ animate หลายร้อยองค์ประกอบพร้อมกัน

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

export function AnimatedCard() {
  const [expanded, setExpanded] = useState(false);
  return (
    <Pressable onPress={() => setExpanded(!expanded)}>
      <View
        className={`transition-all duration-300 rounded-2xl bg-slate-800 ${
          expanded ? "h-64" : "h-24"
        }`}
      >
        <Text className="p-4 text-white">
          {expanded ? "ย่อกลับ" : "แตะเพื่อขยาย"}
        </Text>
      </View>
    </Pressable>
  );
}

สำหรับ keyframe animation เช่น pulse หรือ spinner คุณเขียน @keyframes ใน global.css ได้ตรง ๆ NativeWind จะแปลงเป็น useSharedValue + withRepeat ให้อัตโนมัติ

/* global.css */
@keyframes pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.5; }
}
.animate-pulse {
  animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
}

NativeWind vs StyleSheet vs styled-components

คำถามยอดฮิตคือ "ควรใช้ styling ตัวไหนในปี 2026" คำตอบขึ้นกับทีมและ scale แต่ตารางนี้สรุปข้อดี, ข้อเสียหลัก ๆ ที่ผมเจอจริง จากการใช้ทั้งสามแบบในแอป production (รวมถึงตัวที่มีผู้ใช้หลักแสน)

ประเด็นNativeWind v4StyleSheet ของ RNstyled-components
ความคุ้นเคยของทีม (เว็บ)สูงมาก (syntax เหมือน Tailwind)ต่ำ (ต้องเรียนรู้ API ของ RN)ปานกลาง (คล้าย CSS-in-JS บนเว็บ)
ประสิทธิภาพ runtimeเทียบเท่า StyleSheet (compile ล่วงหน้า)เร็วที่สุด (baseline)ช้ากว่า ~30-40% ตอน mount
Dark ModeBuilt-in ด้วย prefix dark:ต้องเขียน conditional เองThemeProvider + prop
Responsive breakpointsBuilt-in sm/md/lgเรียก useWindowDimensions เองไม่มี (ต้องเขียน media query เอง)
Bundle size (gzip)~40 KB0 KB (in core)~120 KB
รองรับ React Native Webใช่ (isomorphic)ใช่ (native)ใช่
รองรับ New Architectureใช่ ตั้งแต่ v4.0ใช่ใช่ (v6+)
Autocomplete ใน editorยอดเยี่ยม (Tailwind IntelliSense)ดี (TypeScript)ปานกลาง

สรุปสั้น ๆ ถ้าทีมมีคนเขียนเว็บอยู่แล้ว NativeWind ชนะขาด ถ้าเป็นทีม mobile-only ที่คุ้นกับ StyleSheet อยู่แล้วและไม่ค่อยต้องการ Dark Mode หรือ Responsive การอยู่กับ StyleSheet ก็ไม่ผิด styled-components ยังใช้ได้ แต่ผมไม่แนะนำสำหรับโปรเจกต์ใหม่ในปี 2026 เพราะ overhead ตอน runtime สูงเกินไปเทียบกับ NativeWind

ประสิทธิภาพและ Best Practices

คนเข้าใจผิดกันมากว่า utility class เท่ากับประสิทธิภาพต่ำ ในความจริงแล้ว NativeWind v4 คำนวณ style ทั้งหมดตอน build time สิ่งที่ runtime ทำคือ lookup ค่าใน hash map ซึ่งเร็วมาก อย่างไรก็ตามผมยังแนะนำ pattern เหล่านี้เพื่อรีดประสิทธิภาพเพิ่ม

1. ใช้ remapProps สำหรับ custom component

ถ้าคุณสร้าง <MyButton /> ที่ห่อ Pressable อยู่ ให้บอก NativeWind ว่า class ของ MyButton ต้องส่งต่อไปที่ไหน

import { remapProps } from "nativewind";
import { Pressable } from "react-native";

const StyledPressable = remapProps(Pressable, {
  className: "style",
});

2. หลีกเลี่ยง class แบบ dynamic string concat

เพราะ Tailwind สแกน source code ตอน build ถ้าคุณเขียน className={`bg-${color}-500`} Tailwind จะไม่รู้จักและตัดคลาสนั้นทิ้ง ให้ใช้ clsx หรือเขียน conditional เต็ม string แทน

// ผิด
<View className={`bg-${color}-500`} />

// ถูก
import clsx from "clsx";
<View
  className={clsx({
    "bg-red-500": color === "red",
    "bg-blue-500": color === "blue",
  })}
/>

3. Extract component เมื่อ class ยาวเกิน 5 บรรทัด

ถ้าคุณมี class ยาว ๆ ซ้ำในหลายที่ ให้ทำเป็นคอมโพเนนต์แยกหรือใช้ @apply ใน global.css

@layer components {
  .btn-primary {
    @apply px-4 py-2 bg-brand-500 rounded-lg active:opacity-80;
  }
}

Troubleshooting ปัญหาที่พบบ่อย

เอาละ, ผมรวบรวมปัญหาที่ทีมเจอบ่อยที่สุดตอน onboard NativeWind v4 และวิธีแก้ที่ทำได้จริง (ทั้งหมดเจอกับตัวมาแล้ว)

Class ไม่ apply แม้ตั้งค่าถูก

ตรวจสอบว่า content array ใน tailwind.config.js ครอบคลุมทุก path ที่มี className จริง ๆ ถ้าไฟล์ของคุณอยู่ใน src/ ต้องเพิ่ม "./src/**/*.{js,jsx,ts,tsx}" ด้วย จากนั้นรัน npx expo start --clear

Error: "Cannot find module 'nativewind/babel'"

เจอบ่อยหลังอัปเกรด Expo SDK เกิดจาก node_modules เก่าค้าง แก้โดย rm -rf node_modules yarn.lock; yarn install แล้ว cd ios && pod install

Dark mode ไม่เปลี่ยน แม้ระบบเปลี่ยน theme

ตรวจสอบใน app.json ว่ามี "userInterfaceStyle": "automatic" ทั้งใน root และใน iOS/Android block ถ้าไม่มี iOS จะ lock theme ไว้ที่ light ตลอด

Animation ไม่ทำงาน

ตรวจว่า react-native-reanimated/plugin อยู่ท้ายสุดใน babel.config.js และ import "react-native-reanimated" ที่ top ของ entry file ก่อน component แรก ผมเคยลืมทั้งสองข้อพร้อมกัน แล้วนั่งหาต้นเหตุอยู่นาน

คำถามที่พบบ่อย

NativeWind v4 ทำงานกับ React Native New Architecture (Fabric) ไหม?

ใช่ NativeWind v4 ถูกออกแบบให้เข้ากับ Fabric + TurboModules ตั้งแต่ v4.0 stable ไม่ต้องเปิด flag พิเศษหรือใช้ shim ใด ๆ ผู้ใช้ Expo SDK 52+ จะได้ New Architecture เป็นค่าเริ่มต้นและ NativeWind ยังทำงานได้ปกติ

NativeWind v4 ทำให้ bundle size แอปใหญ่ขึ้นเท่าไร?

ประมาณ 40 KB gzip สำหรับ react-native-css-interop runtime ส่วน CSS ที่คุณใช้จริงจะถูก tree-shake โดย Tailwind ทำให้ไม่มี dead code ในกรณีทั่วไป bundle เพิ่มไม่เกิน 60 KB เทียบกับใช้ StyleSheet ล้วน ๆ

ควรใช้ NativeWind หรือ Tamagui ปี 2026?

ถ้าทีมมี background เว็บและอยาก learning curve ต่ำ NativeWind ชนะ ถ้าต้องการ design system ที่มี component library พร้อมและรองรับ compiler-based optimization สำหรับ web + native พร้อมกัน Tamagui เป็นทางเลือกดี แต่ setup ซับซ้อนกว่ามาก

NativeWind รองรับ React Native Web ไหม?

ใช่ และแบบ isomorphic คือคลาสเดียวกัน compile ต่างกันบน native/web โดยอัตโนมัติ เหมาะกับทีมที่ทำ RN + Web จาก codebase เดียว โดยเฉพาะเมื่อใช้กับ Expo Router 4 ที่ตอนนี้รองรับ SSR แล้ว

Class dynamic เช่น bg-red-500 ที่มาจาก state ทำไมไม่ apply?

เพราะ Tailwind สแกน source code ตอน build ไม่ใช่ runtime ถ้าคุณเขียน string concat เช่น bg-${color}-500 Tailwind มองไม่เห็นและตัดคลาสทิ้ง วิธีแก้คือเขียนเต็ม string ทุกกรณีที่เป็นไปได้ หรือใช้ safelist ใน tailwind.config.js เพื่อบอกให้ include คลาสที่ไม่ปรากฏใน source โดยตรง

Jake Morrison
เกี่ยวกับผู้เขียน Jake Morrison

React Native lead engineer who's shipped six apps and learned six different lessons. Bullish on the New Architecture.