NativeWind (Tailwind para RN)
Classes utilitárias, modo escuro e configuração de build no Expo.
Busque em todas as páginas da documentação
Classes utilitárias, modo escuro e configuração de build no Expo.
NativeWind traz a ergonomia do Tailwind CSS para o React Native: className="flex-1 p-4 bg-white dark:bg-slate-900" em vez de objetos StyleSheet espalhados. No Expo SDK 57, NativeWind v4 se integra ao Metro e compila utilitários para estilos RN em tempo de build - não um analisador CSS em tempo de execução no dispositivo.
Cartão de receita de referência rápida - pronto para copiar e colar.
npx create-expo-app@latest MyWindApp --template blank-typescript
cd MyWindApp
npx expo install nativewind tailwindcss@^3.4.0 react-native-reanimated react-native-safe-area-context
npm install --save-dev prettier-plugin-tailwindcss
npx tailwindcss init// tailwind.config.js
/** @type {import('tailwindcss').Config} */
module.exports = {
content: ["./app/**/*.{js,jsx,ts,tsx}", "./components/**/*.{js,jsx,ts,tsx}"],
presets: [require("nativewind/preset")],
theme: {
extend: {
colors: {
brand: { DEFAULT: "#2563eb", muted: "#93c5fd" },
},
},
},
plugins: [],
};/* global.css */
@tailwind base;
@tailwind components;
@tailwind utilities;// 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" });// nativewind-env.d.ts
/// <reference types="nativewind/types" />// app/_layout.tsx (Expo Router) ou App.tsx
import "../global.css";
import { Stack } from "expo-router";
export default function RootLayout() {
return <Stack screenOptions={{ headerShown: false }} />;
}// components/Card.tsx
import { Text, View } from "react-native";
export function Card({ title, body }: { title: string; body: string }) {
return (
<View className="rounded-xl border border-slate-200 bg-white p-4 dark:border-slate-700 dark:bg-slate-900">
<Text className="text-base font-semibold text-slate-900 dark:text-slate-50">{title}</Text>
<Text className="mt-1 text-sm text-slate-600 dark:text-slate-400">{body}</Text>
</View>
);
}Quando usar isso:
StyleSheet está diminuindo a velocidade de desenvolvimento.dark: vinculadas ao esquema do sistema sem a necessidade de manter manualmente duas paletas por componente.md:, lg:) para layouts de tablet junto com os padrões de telefone.Tela de configurações com modo escuro do sistema, tokens de marca semânticos e um botão com estado pressionado.
// app/settings.tsx
import { Pressable, ScrollView, Text, useColorScheme, View } from "react-native";
import { SafeAreaView } from "react-native-safe-area-context";
import { StatusBar } from "expo-status-bar";
const ROWS = [
{ id: "profile", label: "Editar perfil" },
{ id: "notifications", label: "Notificações" },
{ id: "privacy", label: "Privacidade" },
] as const;
export default function SettingsScreen() {
const scheme = useColorScheme() ?? "light";
return (
<SafeAreaView className="flex-1 bg-slate-50 dark:bg-slate-950">
<StatusBar style={scheme === "dark" ? "light" : "dark"} />
<ScrollView contentContainerClassName="gap-3 p-4">
<Text className="text-2xl font-bold text-slate-900 dark:text-slate-50">Configurações</Text>
<View className="overflow-hidden rounded-xl border border-slate-200 bg-white dark:border-slate-800 dark:bg-slate-900">
{ROWS.map((row) => (
<Pressable
key={row.id}
accessibilityRole="button"
className="border-b border-slate-100 px-4 py-3.5 active:bg-slate-100 dark:border-slate-800 dark:active:bg-slate-800"
>
<Text className="text-base text-slate-900 dark:text-slate-100">{row.label}</Text>
</Pressable>
))}
</View>
<Pressable
accessibilityRole="button"
className="items-center rounded-xl bg-brand px-4 py-3.5 active:opacity-80"
>
<Text className="text-base font-semibold text-white">Salvar alterações</Text>
</Pressable>
</ScrollView>
</SafeAreaView>
);
}// tailwind.config.js - darkMode para utilitários dark: baseados em classe
module.exports = {
content: ["./app/**/*.{js,jsx,ts,tsx}", "./components/**/*.{js,jsx,ts,tsx}"],
presets: [require("nativewind/preset")],
darkMode: "class",
theme: {
extend: {
colors: {
brand: { DEFAULT: "#2563eb", foreground: "#ffffff" },
},
},
},
};// providers/ThemeModeProvider.tsx - substituição opcional no aplicativo
import { createContext, useContext, useEffect, useState } from "react";
import { Appearance, useColorScheme } from "react-native";
import { colorScheme } from "nativewind";
type Mode = "light" | "dark" | "system";
const ThemeModeContext = createContext<{ mode: Mode; setMode: (m: Mode) => void }>({
mode: "system",
setMode: () => {},
});
export function ThemeModeProvider({ children }: { children: React.ReactNode }) {
const system = useColorScheme();
const [mode, setMode] = useState<Mode>("system");
useEffect(() => {
if (mode === "system") {
Appearance.setColorScheme(null);
colorScheme.set(system === "dark" ? "dark" : "light");
} else {
Appearance.setColorScheme(mode);
colorScheme.set(mode);
}
}, [mode, system]);
return (
<ThemeModeContext.Provider value={{ mode, setMode }}>{children}</ThemeModeContext.Provider>
);
}
export function useThemeMode() {
return useContext(ThemeModeContext);
}O que isso demonstra:
withNativeWind no Metro compila global.css e conecta className a primitivas RN.dark: respondem à API colorScheme do NativeWind sincronizada com useColorScheme.contentContainerClassName em ScrollView aplica utilitários ao wrapper de conteúdo de rolagem.brand em theme.extend - as telas usam bg-brand, não hex direto.active: para feedback de pressionamento sem estado StyleSheet inline.nativewind/preset mapeia utilitários Tailwind da web para propriedades suportadas por RN - CSS não suportado é removido ou avisado em desenvolvimento.className não é uma prop nativa - NativeWind corrige componentes suportados (View, Text, Pressable, etc.) através de jsxImportSource ou plugin Babel, dependendo da configuração.darkMode: "class", chame colorScheme.set("dark") de nativewind ao substituir a aparência do sistema; classes dark: são ativadas de acordo.tailwind.config.js theme.extend; as telas consomem utilitários, não valores arbitrários únicos text-[#334155].| Preocupação | StyleSheet + tokens | NativeWind |
|---|---|---|
| Curva de aprendizado | Nativo do RN | Vocabulário Tailwind |
| Sobrecarga de bundle | Mínima | Piso de configuração + compilador |
| Modo escuro | Objeto de tema manual | Variantes dark: |
| Caminhos críticos de lista | Referências estáveis fáceis | Mantenha strings de classe estáticas |
| Entrega ao designer | Tabela de tokens | Especificação de classe utilitária |
// nativewind-env.d.ts
/// <reference types="nativewind/types" />className tenha tipagem em componentes RN.className, use cssInterop do NativeWind para mapear className → style.renderItem de listas - literais de modelo dinâmicos prejudicam a extração em tempo de compilação.// app/_layout.tsx
import "../global.css";
import { ThemeModeProvider } from "../providers/ThemeModeProvider";
import { Stack } from "expo-router";
export default function RootLayout() {
return (
<ThemeModeProvider>
<Stack />
</ThemeModeProvider>
);
}Importe global.css uma vez no layout raiz - rotas filhas herdam utilitários compilados.
Caminhos content ausentes - Tailwind remove classes não utilizadas; se ./app/** for omitido, os estilos desaparecerão silenciosamente. Correção: Inclua todas as pastas com strings className.
Importação global.css esquecida - Utilitários nunca são registrados. Correção: Importe no App.tsx raiz ou app/_layout.tsx.
Cache do Metro desatualizado após alteração de configuração - Estilos antigos persistem. Correção: npx expo start --clear após edições em tailwind.config.js.
Valores arbitrários em todos os lugares - p-[13px] ignora sua escala. Correção: Estenda theme.spacing e aplique em revisão de código.
Concatenação dinâmica de classes em listas - `bg-${color}-500` quebra a extração em tempo de compilação. Correção: Use um mapa fixo: const bg = { red: "bg-red-500", blue: "bg-blue-500" }.
dark: sem sincronizar colorScheme - O alternador no aplicativo muda Appearance, mas não o NativeWind. Correção: Chame colorScheme.set() em seu provedor de tema.
TextInput de terceiros ignora className - Nem todos os componentes são corrigidos. Correção: cssInterop(TextInput, { className: "style" }) em um arquivo de configuração.
| Alternativa | Usar Quando | Não Usar Quando |
|---|---|---|
| NativeWind v4 | Equipe Tailwind, muitas telas, variantes escuras | Aplicativo de duas telas com cinco estilos |
| StyleSheet + tokens | Dependências mínimas, controle total | Designers exigem fluxo de trabalho de utilitários |
| Tamagui | Tokens compilados + componentes + web | Você quer apenas strings de classe, não um kit de componentes |
| React Native Paper | Componentes Material prontos para uso | Marca personalizada não relacionada ao MD3 |
| Unistyles | Temas em tempo de execução com breakpoints | Equipe não tem experiência com bibliotecas de estilo RN |
Sim. Instale via npx expo install nativewind tailwindcss react-native-reanimated, envolva o Metro com withNativeWind e importe global.css na raiz do aplicativo. Limpe o cache do Metro após alterações de configuração.
Em tailwind.config.js em theme.extend - cores, espaçamento, fontSize, borderRadius. As telas referenciam text-brand, p-md, não valores brutos. Alinhe os nomes com Noções Básicas de Sistemas de Design.
Defina darkMode: "class" e use utilitários dark:bg-slate-900. Sincronize com o sistema via useColorScheme, ou substitua com colorScheme.set("dark") de nativewind quando o usuário escolher um tema no aplicativo. Veja Modo Escuro e Esquemas de Cores.
Sim. Importe global.css em app/_layout.tsx. Adicione ./app/**/* aos caminhos content do Tailwind.
Trate className como uma camada base e passe style para valores verdadeiramente dinâmicos (largura animada). Evite duplicar a mesma propriedade em ambos.
NativeWind tem como alvo visualizações React Native. O Expo web pode renderizar alguns utilitários, mas valide o layout separadamente - problemas específicos da web pertencem a Noções Básicas de Estilo.
Carregue fontes com expo-font, depois mapeie fontFamily em tailwind.config.js theme.extend. Veja Escala de Tipografia e Carregamento de Fontes.
Mantenha strings className estáticas em componentes de linha. Extraia linhas para filhos memo(). Verifique o desempenho antes de assumir que os utilitários são gratuitos - veja Desempenho de Estilo.
AppearanceaccessibilityRole em pressables estilizadosVersões do Stack: Esta página foi escrita para React 19.2.3, React Native 0.86.0 e Expo SDK 57 (
expo~57.0.4).
Revisado por Chris St. John·Última atualização: 16 de jul. de 2026