Overview
The withUniwind higher-order component (HOC) wraps any React Native component to add className prop support. This is essential for using third-party components with Uniwind’s Tailwind-based styling system.
Why Use withUniwind?
Many popular React Native libraries export components that don’t natively support the className prop. Instead, they accept the traditional style prop. The withUniwind wrapper bridges this gap, allowing you to use Tailwind classes with any component.
Some third-party components work out of the box! Libraries like React Native Reanimated that are built on top of React Native’s core components (View, Text, etc.) automatically support className without wrapping. You only need withUniwind when the underlying implementation uses custom native components or doesn’t forward the style prop properly.
Problem
import { SafeAreaView } from 'react-native-safe-area-context';
// ❌ This won't work - SafeAreaView is a third-party component
<SafeAreaView className="flex-1 bg-background">
{/* content */}
</SafeAreaView>
Solution
import { withUniwind } from 'uniwind'
import { SafeAreaView } from 'react-native-safe-area-context';
const StyledSafeAreaView = withUniwind(SafeAreaView);
// ✅ This works - we've wrapped the component with withUniwind
<StyledSafeAreaView className="flex-1 bg-background">
{/* content */}
</StyledSafeAreaView>
Automatic Prop Mapping
withUniwind automatically maps props based on their names. Any prop containing style or color in its name is automatically mapped.
No manual mapping needed! The style prop is automatically mapped to className, and color-related props get their own *ClassName variants.
Automatic Mappings
Here are some examples of how props are automatically mapped:
| Original Prop | Mapped ClassName Prop | Example Usage |
|---|
style | className | <Component className="p-4" /> |
color | colorClassName | <Component colorClassName="accent-red-500" /> |
backgroundColor | backgroundColorClassName | <Component backgroundColorClassName="accent-blue-500" /> |
borderColor | borderColorClassName | <Component borderColorClassName="accent-gray-300" /> |
tintColor | tintColorClassName | <Component tintColorClassName="accent-green-500" /> |
Example: Using Auto-Mapped Color Props
import { withUniwind } from 'uniwind'
import { ActivityIndicator } from 'react-native-activity-indicator'
const StyledActivityIndicator = withUniwind(ActivityIndicator)
// Use colorClassName instead of the color prop
<StyledActivityIndicator
colorClassName="accent-blue-500 dark:accent-blue-300"
size="large"
/>
Custom Prop Mapping
For advanced use cases, you can define custom mappings to map specific props to style properties. This is particularly useful for SVG components or components with non-standard prop names.
Mapping with Style Properties
Map a custom className prop to a specific CSS property:
import { withUniwind } from 'uniwind'
import { Path } from 'react-native-svg'
export const StyledPath = withUniwind(Path, {
stroke: {
fromClassName: 'strokeClassName',
styleProperty: 'accentColor',
},
})
// Usage: strokeClassName maps to stroke, using accentColor from the class
<StyledPath strokeClassName="accent-red-500 dark:accent-blue-100" />
In this example:
strokeClassName is the new prop you’ll use in JSX
stroke is the original component prop being mapped
accentColor is the CSS property to extract from the className
Mapping Background Colors
You can map any style property, including background colors:
import { withUniwind } from 'uniwind'
import { Path } from 'react-native-svg'
export const StyledPath = withUniwind(Path, {
stroke: {
fromClassName: 'strokeClassName',
styleProperty: 'backgroundColor',
},
})
// Usage: strokeClassName maps to stroke, using backgroundColor
<StyledPath strokeClassName="bg-red-500 dark:bg-blue-500" />
Mapping Entire Style Objects
If you omit the styleProperty, withUniwind will map the entire resolved style object instead of a single property:
import { withUniwind } from 'uniwind'
import { CustomComponent } from 'some-library'
export const StyledCustomComponent = withUniwind(CustomComponent, {
customProp: {
fromClassName: 'customClassName',
// No styleProperty - maps the entire style object
},
})
// Usage: All styles from customClassName are applied to customProp
<StyledCustomComponent customClassName="p-4 bg-red-500 rounded-lg" />
Third-Party UI Components
import { withUniwind } from 'uniwind'
import { Button } from 'react-native-paper'
const StyledButton = withUniwind(Button)
export const MyButton = () => (
<StyledButton
className="m-4"
backgroundColorClassName="accent-blue-500"
mode="contained"
>
Press me
</StyledButton>
)
API Reference
Function Signature
withUniwind<T>(Component: T, mappings?: PropMappings): T
Parameters
Component
React.ComponentType
required
The React component to wrap with className support.
Optional custom prop mappings. Each mapping defines how to convert a className prop to a component prop.Mapping structure:{
[targetProp: string]: {
fromClassName: string, // The className prop name to create
styleProperty?: string // Optional CSS property to extract (omit to use entire style)
}
}
Return Value
A wrapped component that accepts className and auto-generated *ClassName props, in addition to all original component props.
Best Practices
Create reusable styled components: Define your wrapped components in a separate file and export them for reuse throughout your app.
// components/styled.ts
import { withUniwind } from 'uniwind'
import { SafeAreaView } from 'react-native-safe-area-context'
import { KeyboardAwareScrollView } from 'react-native-keyboard-aware-scroll-view'
export const StyledSafeAreaView = withUniwind(SafeAreaView)
export const StyledKeyboardAwareScrollView = withUniwind(KeyboardAwareScrollView)
Performance consideration: Wrap components at the module level (outside your component functions) to avoid recreating the wrapper on every render.