Overview
NativeWind provides full TypeScript support with automatic type generation for the className prop. This guide covers setup, configuration, and best practices for using TypeScript with NativeWind.
NativeWind automatically generates TypeScript declarations when you run your Metro bundler.
Automatic Type Generation
NativeWind generates a nativewind-env.d.ts file that adds the className prop to all React Native components.
Configure Metro
The withNativewind Metro wrapper automatically generates types: const { getDefaultConfig } = require ( "expo/metro-config" );
const { withNativewind } = require ( "nativewind/metro" );
const config = getDefaultConfig ( __dirname );
module . exports = withNativewind ( config , {
typescriptEnvPath: "nativewind-env.d.ts" , // Default path
});
Run your dev server
Start Metro to generate the type declarations: npm start
# or
expo start
This creates nativewind-env.d.ts in your project root: /// < reference types = "react-native-css/types" />
// NOTE: This file should not be edited and should be committed
// with your source code. It is generated by react-native-css.
Include in tsconfig.json
Ensure the generated file is included in your TypeScript configuration: {
"extends" : "expo/tsconfig.base" ,
"compilerOptions" : {
"strict" : true ,
"noEmit" : true ,
"allowJs" : true
},
"include" : [
"**/*.ts" ,
"**/*.tsx" ,
"nativewind-env.d.ts"
]
}
TypeScript Configuration
Recommended tsconfig.json
For optimal TypeScript support with NativeWind:
{
"extends" : "expo/tsconfig.base" ,
"compilerOptions" : {
// Strict mode for better type safety
"strict" : true ,
"strictNullChecks" : true ,
"strictFunctionTypes" : true ,
// Module resolution
"moduleResolution" : "node" ,
"resolveJsonModule" : true ,
"esModuleInterop" : true ,
// Project settings
"allowJs" : true ,
"noEmit" : true ,
"skipLibCheck" : true ,
// Path aliases (optional)
"baseUrl" : "." ,
"paths" : {
"@/*" : [ "src/*" ]
}
},
"include" : [
"**/*.ts" ,
"**/*.tsx" ,
"nativewind-env.d.ts" ,
"global.css"
],
"exclude" : [
"node_modules"
]
}
Custom Type Paths
If you use compilerOptions.types to manage type inclusion:
{
"compilerOptions" : {
"types" : [
"react-native" ,
"react-native-css/types"
]
}
}
Disable auto-generation to avoid conflicts:
module . exports = withNativewind ( config , {
disableTypeScriptGeneration: true ,
});
Using TypeScript with NativeWind
Basic Usage
The className prop is now type-safe on all React Native components:
import { View , Text , Pressable } from "react-native" ;
export default function Example () {
return (
< View className = "flex-1 bg-white p-4" >
< Text className = "text-2xl font-bold text-gray-900" >
TypeScript + NativeWind
</ Text >
< Pressable className = "mt-4 bg-blue-500 px-6 py-3 rounded-lg" >
< Text className = "text-white font-semibold" > Press me </ Text >
</ Pressable >
</ View >
);
}
Typed Component Props
Create reusable components with typed props:
import { View , Text , type ViewProps } from "react-native" ;
import type { PropsWithChildren } from "react" ;
interface CardProps extends PropsWithChildren {
title : string ;
variant ?: "primary" | "secondary" ;
className ?: string ;
}
export function Card ({ title , variant = "primary" , className , children } : CardProps ) {
const variantStyles = {
primary: "bg-blue-500 border-blue-600" ,
secondary: "bg-gray-500 border-gray-600" ,
};
return (
< View className = { `rounded-lg border-2 p-4 ${ variantStyles [ variant ] } ${ className || "" } ` } >
< Text className = "text-xl font-bold text-white mb-2" > { title } </ Text >
{ children }
</ View >
);
}
Usage:
< Card title = "Welcome" variant = "primary" className = "mt-4" >
< Text className = "text-white" > Card content </ Text >
</ Card >
Styled Components Pattern
Create typed styled components using NativeWind’s styled function:
import { styled } from "nativewind" ;
import { View , Text , Pressable } from "react-native" ;
// Styled components with TypeScript
const Container = styled ( View , "flex-1 bg-white p-4" );
const Title = styled ( Text , "text-2xl font-bold text-gray-900" );
const Button = styled ( Pressable , "bg-blue-500 px-6 py-3 rounded-lg active:bg-blue-600" );
const ButtonText = styled ( Text , "text-white font-semibold text-center" );
export default function StyledExample () {
return (
< Container >
< Title > Styled Components </ Title >
< Button onPress = { () => console . log ( "Pressed" ) } >
< ButtonText > Press me </ ButtonText >
</ Button >
</ Container >
);
}
CSS Variables with TypeScript
Use typed CSS variables with the vars helper:
import { View , Text } from "react-native" ;
import { vars , VariableContextProvider } from "nativewind" ;
import { useState } from "react" ;
interface ThemeVariables {
"--primary-color" : string ;
"--text-size" : number ;
}
export default function VariablesExample () {
const [ theme , setTheme ] = useState < ThemeVariables >({
"--primary-color" : "#3b82f6" ,
"--text-size" : 16 ,
});
return (
< VariableContextProvider value = { vars ( theme ) } >
< View className = "flex-1 items-center justify-center"
style = { { backgroundColor: "var(--primary-color)" } } >
< Text className = "text-white"
style = { { fontSize: "var(--text-size)" } } >
Themed Content
</ Text >
</ View >
</ VariableContextProvider >
);
}
Type-Safe Hooks
NativeWind exports typed hooks from react-native-css:
import { useCssElement , useUnstableNativeVariable } from "nativewind" ;
import { View } from "react-native" ;
function TypedHooksExample () {
// Type-safe CSS element hook
const cssProps = useCssElement ({
className: "bg-blue-500 p-4 rounded-lg" ,
});
// Type-safe native variable hook
const backgroundColor = useUnstableNativeVariable ( "--color-primary" );
return < View { ... cssProps } /> ;
}
Advanced TypeScript Patterns
Conditional Class Names
Create a type-safe className utility:
type ClassValue = string | undefined | null | false ;
function cn ( ... classes : ClassValue []) : string {
return classes . filter ( Boolean ). join ( " " );
}
// Usage
function Button ({ primary , disabled } : { primary ?: boolean ; disabled ?: boolean }) {
return (
< Pressable
className = { cn (
"px-4 py-2 rounded" ,
primary && "bg-blue-500" ,
disabled && "opacity-50" ,
! primary && "bg-gray-500"
) }
>
< Text className = "text-white" > Button </ Text >
</ Pressable >
);
}
Variant Props Pattern
Create components with typed variants:
import { cva , type VariantProps } from "class-variance-authority" ;
import { Pressable , Text } from "react-native" ;
import type { PropsWithChildren } from "react" ;
const buttonVariants = cva (
"rounded-lg font-semibold text-center" ,
{
variants: {
variant: {
primary: "bg-blue-500 text-white" ,
secondary: "bg-gray-500 text-white" ,
outline: "border-2 border-blue-500 text-blue-500" ,
},
size: {
sm: "px-3 py-1.5 text-sm" ,
md: "px-4 py-2 text-base" ,
lg: "px-6 py-3 text-lg" ,
},
},
defaultVariants: {
variant: "primary" ,
size: "md" ,
},
}
);
interface ButtonProps extends PropsWithChildren , VariantProps < typeof buttonVariants > {
onPress ?: () => void ;
}
export function Button ({ variant , size , onPress , children } : ButtonProps ) {
return (
< Pressable className = { buttonVariants ({ variant , size }) } onPress = { onPress } >
< Text className = "text-inherit" > { children } </ Text >
</ Pressable >
);
}
// Type-safe usage
< Button variant = "outline" size = "lg" onPress = { () => {} } >
Click me
</ Button >
Generic Styled Components
Create generic typed components:
import { ComponentType } from "react" ;
import { View , Text , type ViewProps , type TextProps } from "react-native" ;
function createStyledComponent < T extends ViewProps | TextProps >(
Component : ComponentType < T >,
baseClassName : string
) {
return ( props : T & { className ?: string }) => {
const combinedClassName = ` ${ baseClassName } ${ props . className || "" } ` . trim ();
return < Component { ... props } className = { combinedClassName } /> ;
};
}
const Card = createStyledComponent ( View , "bg-white rounded-lg shadow-md p-4" );
const Heading = createStyledComponent ( Text , "text-2xl font-bold" );
Troubleshooting TypeScript
className prop not recognized
Problem : TypeScript shows error: Property 'className' does not exist on type 'ViewProps'Solution :
Ensure nativewind-env.d.ts is generated and included in tsconfig.json
Restart your TypeScript server in VSCode (Cmd/Ctrl + Shift + P > “TypeScript: Restart TS Server”)
Clear Metro cache: expo start --clear
{
"include" : [
"**/*.ts" ,
"**/*.tsx" ,
"nativewind-env.d.ts" // Must be included
]
}
Problem : Changes to CSS not reflected in TypeScriptSolution :
Restart Metro bundler
Delete nativewind-env.d.ts and restart
Run: expo start --clear
Conflicting type declarations
Problem : Multiple type declaration conflictsSolution : If using custom type paths, disable auto-generation:module . exports = withNativewind ( config , {
disableTypeScriptGeneration: true ,
});
Then manually add types to your tsconfig.json: {
"compilerOptions" : {
"types" : [ "react-native-css/types" ]
}
}
styled function type errors
Problem : styled function shows type errorsSolution : Ensure you’re importing from the correct package:import { styled } from "nativewind" ; // Correct
// not from "nativewind/styled" or other paths
Best Practices
Commit generated types
Always commit nativewind-env.d.ts to version control so team members have types immediately.
Use strict mode
Enable TypeScript strict mode for better type safety: {
"compilerOptions" : {
"strict" : true
}
}
Type your components
Always define prop interfaces for reusable components: interface ComponentProps {
title : string ;
className ?: string ; // Optional className override
}
Use const assertions
Use as const for better type inference with variants: const variants = {
primary: "bg-blue-500" ,
secondary: "bg-gray-500" ,
} as const ;
type Variant = keyof typeof variants ;
Next Steps
Configuration Learn about Metro and Babel configuration
Custom Styles Create type-safe custom utilities
API Reference Explore the styled function API
Troubleshooting Common TypeScript issues