Overview
NativeWind provides powerful tools for creating custom utilities and styling patterns that extend beyond Tailwind’s defaults. This guide covers custom utilities, React Native-specific styles, and advanced patterns.
NativeWind v5 uses CSS-based configuration with @utility, @theme, and @custom-variant directives.
Custom Utilities
Create custom utility classes using the @utility directive in your CSS.
Basic Custom Utilities
Define custom utilities in your global.css:
@import "tailwindcss/theme.css" layer(theme);
@import "tailwindcss/preflight.css" layer(base);
@import "tailwindcss/utilities.css" ;
@import "nativewind/theme" ;
/* Custom color utility */
@utility color-* {
color: --value(--color- * );
}
/* Custom tint utility for Image components */
@utility tint-* {
-rn-tint: --value(--color- * );
@prop -rn-tint tint;
}
Usage:
import { Image , Text } from "react-native" ;
< Text className = "color-blue-500" > Custom color utility </ Text >
< Image source = { require ( './icon.png' ) } className = "tint-red-500" />
React Native-Specific Utilities
NativeWind includes custom utilities for React Native features:
Elevation (Android)
Create elevation utilities for Android shadows:
@theme {
--elevation-xs: 1;
--elevation-sm: 3;
--elevation-md: 6;
--elevation-lg: 8;
--elevation-xl: 13;
--elevation-2xl: 24;
--elevation-none: 0;
}
@utility elevation-* {
-rn-elevation: --value(--elevation- * );
}
Usage:
< View className = "android:elevation-md ios:shadow-lg" >
< Text > Platform-specific shadows </ Text >
</ View >
Ripple Effect (Android)
Custom ripple utilities for Android pressable feedback:
@utility ripple-* {
-rn-ripple-style: --value("borderless");
-rn-ripple-color: --value(--color- * );
}
@utility ripple-* {
-rn-ripple-radius: --value(integer);
}
@utility ripple-foreground {
-rn-ripple-foreground: "foreground";
}
Usage:
import { Pressable , Text } from "react-native" ;
< Pressable className = "ripple-blue-500 ripple-borderless" >
< Text > Press me </ Text >
</ Pressable >
Corner Shapes
Custom corner shapes for iOS:
@utility corner-* {
corner-shape : --value("rounded", "squircle");
}
Usage:
< View className = "corner-squircle bg-blue-500 p-4" >
< Text className = "text-white" > Squircle corners </ Text >
</ View >
Line Height Override
NativeWind overrides Tailwind’s line-height to work with React Native’s unitless requirement:
/**
* Override leading-* utility to use unitless values
* React Native requires unitless line-height values
*/
@utility leading-* {
line-height : calc(var(--spacing) / 1rem * --value(integer));
}
Usage:
< Text className = "text-2xl leading-8" > Custom line height </ Text >
Custom Theme Tokens
Extend the theme with custom design tokens using @theme:
@theme {
/* Custom colors */
--color-brand-primary: #38bdf8 ;
--color-brand-secondary: #0ea5e9 ;
--color-brand-accent: #7dd3fc ;
/* Custom spacing */
--spacing-xs: 0.25rem;
--spacing-2xs: 0.125rem;
/* Custom elevations */
--elevation-card: 6;
--elevation-modal: 24;
/* Custom border radius */
--radius-card: 12px;
--radius-button: 8px;
}
Usage:
< View className = "bg-brand-primary rounded-[--radius-card] p-4" >
< Text className = "text-brand-secondary" > Themed card </ Text >
</ View >
NativeWind provides built-in platform modifiers:
@custom-variant ios (@media ios);
@custom-variant android (@media android);
@custom-variant native (@media native);
@custom-variant tv (@media (display-mode: tv));
@custom-variant web (@supports selector(div > div));
Usage:
< View className = "ios:bg-blue-500 android:bg-green-500 web:bg-red-500" >
< Text className = "native:text-white web:text-black" > Platform styles </ Text >
</ View >
Define platform-specific font families:
:root {
@ media ios {
--font-sans : System ;
--font-serif : Georgia ;
--font-mono : Menlo;
}
@media android {
--font-sans: SystemAndroid;
--font-serif: sans-serif ;
--font-mono: monospace;
}
}
Usage:
< Text className = "font-sans" > Platform-specific font </ Text >
Styled Components Pattern
Create reusable styled components using NativeWind’s styled function:
Basic Styled Components
import { styled } from "nativewind" ;
import { View , Text , Pressable } from "react-native" ;
const Container = styled ( View , "flex-1 bg-white p-4" );
const Title = styled ( Text , "text-2xl font-bold text-gray-900 mb-2" );
const Subtitle = styled ( Text , "text-base text-gray-600 mb-4" );
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 >
< Subtitle > Built with NativeWind </ Subtitle >
< Button onPress = { () => console . log ( "Pressed" ) } >
< ButtonText > Press me </ ButtonText >
</ Button >
</ Container >
);
}
Conditional Styled Components
Combine styled components with conditional classes:
import { styled } from "nativewind" ;
import { Pressable , Text } from "react-native" ;
const Button = styled ( Pressable );
const ButtonText = styled ( Text );
function CustomButton ({ variant = "primary" , children , ... props }) {
const variants = {
primary: "bg-blue-500 active:bg-blue-600" ,
secondary: "bg-gray-500 active:bg-gray-600" ,
danger: "bg-red-500 active:bg-red-600" ,
};
const textVariants = {
primary: "text-white" ,
secondary: "text-white" ,
danger: "text-white" ,
};
return (
< Button className = { `px-6 py-3 rounded-lg ${ variants [ variant ] } ` } { ... props } >
< ButtonText className = { `font-semibold text-center ${ textVariants [ variant ] } ` } >
{ children }
</ ButtonText >
</ Button >
);
}
CSS Variables Integration
Use CSS variables for dynamic theming and runtime styling:
Basic CSS Variables
import { View , Text } from "react-native" ;
import { vars , VariableContextProvider } from "nativewind" ;
function ThemedComponent () {
const theme = vars ({
"--primary-color" : "#3b82f6" ,
"--secondary-color" : "#64748b" ,
"--text-size" : 16 ,
});
return (
< VariableContextProvider value = { theme } >
< View style = { { backgroundColor: "var(--primary-color)" } } >
< Text style = { { color: "var(--secondary-color)" , fontSize: "var(--text-size)" } } >
Themed content
</ Text >
</ View >
</ VariableContextProvider >
);
}
Dynamic Theme Switching
import { useState } from "react" ;
import { View , Text , Pressable } from "react-native" ;
import { vars , VariableContextProvider } from "nativewind" ;
const themes = {
light: vars ({
"--bg-color" : "#ffffff" ,
"--text-color" : "#000000" ,
}),
dark: vars ({
"--bg-color" : "#1a1a1a" ,
"--text-color" : "#ffffff" ,
}),
};
export default function DynamicTheme () {
const [ theme , setTheme ] = useState < "light" | "dark" >( "light" );
return (
< VariableContextProvider value = { themes [ theme ] } >
< View className = "flex-1" style = { { backgroundColor: "var(--bg-color)" } } >
< Text style = { { color: "var(--text-color)" } } > Current theme: { theme } </ Text >
< Pressable
className = "mt-4 px-6 py-3 bg-blue-500 rounded-lg"
onPress = { () => setTheme ( theme === "light" ? "dark" : "light" ) }
>
< Text className = "text-white" > Toggle Theme </ Text >
</ Pressable >
</ View >
</ VariableContextProvider >
);
}
Advanced Patterns
Variant-Based Components
Create components with multiple variants:
import { Pressable , Text , View } from "react-native" ;
import type { PropsWithChildren } from "react" ;
interface CardProps extends PropsWithChildren {
variant ?: "elevated" | "outlined" | "filled" ;
color ?: "primary" | "secondary" | "neutral" ;
}
export function Card ({ variant = "elevated" , color = "neutral" , children } : CardProps ) {
const variantStyles = {
elevated: "shadow-lg" ,
outlined: "border-2" ,
filled: "" ,
};
const colorStyles = {
primary: {
elevated: "bg-white border-blue-500" ,
outlined: "bg-transparent border-blue-500" ,
filled: "bg-blue-500" ,
},
secondary: {
elevated: "bg-white border-gray-500" ,
outlined: "bg-transparent border-gray-500" ,
filled: "bg-gray-500" ,
},
neutral: {
elevated: "bg-white border-gray-200" ,
outlined: "bg-transparent border-gray-300" ,
filled: "bg-gray-100" ,
},
};
return (
< View className = { `rounded-lg p-4 ${ variantStyles [ variant ] } ${ colorStyles [ color ][ variant ] } ` } >
{ children }
</ View >
);
}
Utility Class Helper
Create a utility for combining class names:
type ClassValue = string | undefined | null | false ;
export function cn ( ... classes : ClassValue []) : string {
return classes . filter ( Boolean ). join ( " " );
}
// Usage
function Button ({ primary , disabled , className }) {
return (
< Pressable
className = { cn (
"px-4 py-2 rounded-lg" ,
primary ? "bg-blue-500" : "bg-gray-500" ,
disabled && "opacity-50" ,
className
) }
>
< Text className = "text-white" > Button </ Text >
</ Pressable >
);
}
Compound Component Pattern
import { View , Text } from "react-native" ;
import type { PropsWithChildren , ReactNode } from "react" ;
interface CardComposition {
Header : typeof CardHeader ;
Body : typeof CardBody ;
Footer : typeof CardFooter ;
}
function CardHeader ({ children } : PropsWithChildren ) {
return (
< View className = "border-b border-gray-200 pb-3 mb-3" >
< Text className = "text-xl font-bold" > { children } </ Text >
</ View >
);
}
function CardBody ({ children } : PropsWithChildren ) {
return < View className = "mb-3" > { children } </ View > ;
}
function CardFooter ({ children } : PropsWithChildren ) {
return < View className = "border-t border-gray-200 pt-3 mt-3" > { children } </ View > ;
}
const Card : React . FC < PropsWithChildren > & CardComposition = ({ children }) => {
return < View className = "bg-white rounded-lg shadow-lg p-4" > { children } </ View > ;
};
Card . Header = CardHeader ;
Card . Body = CardBody ;
Card . Footer = CardFooter ;
export { Card };
// Usage
< Card >
< Card.Header > Card Title </ Card.Header >
< Card.Body >
< Text > Card content goes here </ Text >
</ Card.Body >
< Card.Footer >
< Text className = "text-gray-500 text-sm" > Footer text </ Text >
</ Card.Footer >
</ Card >
Native Mapping Variant
NativeWind includes a special @map variant for advanced property mapping:
/* Automatically generated by NativeWind */
@custom-variant @map (
/* Maps CSS properties to React Native props */
);
This variant enables advanced mappings like:
< Pressable className = "@map/android_ripple:bg-blue-500" >
< Text > Mapped property </ Text >
</ Pressable >
Best Practices
Keep utilities atomic
Create single-purpose utilities that do one thing well: /* Good */
@utility tint-* {
-rn-tint: --value(--color- * );
}
/* Avoid combining multiple properties */
Use theme tokens
Define reusable theme tokens instead of hardcoded values: @theme {
--elevation-card: 6;
}
@utility elevation-card {
-rn-elevation: var(--elevation-card);
}
Platform-specific defaults
Use platform modifiers for appropriate defaults: < View className = "android:elevation-md ios:shadow-lg" >
Type your components
Always add TypeScript types to custom components: interface CustomButtonProps {
variant : "primary" | "secondary" ;
onPress : () => void ;
}
Next Steps
Configuration Advanced Metro and Tailwind configuration
TypeScript Type-safe custom utilities
Theming Learn about theming in depth
API Reference Complete API documentation