Skip to main content

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:
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:
global.css
@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:
global.css
@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:
global.css
@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:
global.css
/**
 * 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:
global.css
@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>

Platform-Specific Styling

Custom Platform Modifiers

NativeWind provides built-in platform modifiers:
global.css
@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>

Platform-Specific Fonts

Define platform-specific font families:
global.css
: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:
global.css
/* 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

1

Keep utilities atomic

Create single-purpose utilities that do one thing well:
/* Good */
@utility tint-* {
  -rn-tint: --value(--color-*);
}

/* Avoid combining multiple properties */
2

Use theme tokens

Define reusable theme tokens instead of hardcoded values:
@theme {
  --elevation-card: 6;
}

@utility elevation-card {
  -rn-elevation: var(--elevation-card);
}
3

Platform-specific defaults

Use platform modifiers for appropriate defaults:
<View className="android:elevation-md ios:shadow-lg">
4

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