Common Questions
How do I include custom fonts?
How do I include custom fonts?
Custom fonts require two steps: loading the font files into your app and configuring the font names in your CSS. Uniwind maps This will copy your font files to the native iOS and Android projects.
className props to font families, but the actual font files need to be included separately.Important: Uniwind only handles the mapping of classNames to font families. You must include and load the font files separately using Expo Font or React Native’s asset system.
Expo Projects
Step 1: Install and configure expo-font
Add the font files to your project and configure them inapp.json:app.json
Step 2: Define font families in global.css
Configure your font families and text sizes using CSS variables in the@theme directive:global.css
Step 3: Use font classes in your components
Now you can use the configured font families with Tailwind classes:Bare React Native Projects
For bare React Native projects without Expo, you can include fonts using thereact-native.config.js file:Step 1: Create react-native.config.js
react-native.config.js
Step 2: Link the fonts
Run the following command to link your fonts:Step 3: Configure in global.css
After linking the fonts, configure them in yourglobal.css the same way as Expo projects:global.css
Platform-Specific Fonts
You can define different fonts for different platforms using media queries:global.css
Troubleshooting
Fonts not loading
If your fonts aren’t appearing:- Check font file names - Make sure the font family name in CSS matches the font file name exactly
- Rebuild the app - Font changes require a full rebuild, not just a Metro refresh
- Verify file paths - Ensure the paths in
app.jsonorreact-native.config.jsare correct - Clear cache - Try clearing Metro bundler cache with
npx expo start --clear
Font looks different than expected
React Native doesn’t support dynamic font weights. Each weight requires its own font file. Make sure you’ve:- Included all the font weight variants you need
- Mapped each variant to a CSS variable in
@theme - Used the correct className for each weight
Platform Selectors
Learn more about using platform-specific styles
Where should I put global.css in Expo Router?
Where should I put global.css in Expo Router?
When using Expo Router, it’s recommended to place your Then import it in And update Metro config:
global.css file in the project root and import it in your root layout file.Recommended Setup
Step 1: Create global.css in the project root
Place yourglobal.css file in the root of your project:global.css
Step 2: Import in your root layout
Import the CSS file in your root layout file (app/_layout.tsx):app/_layout.tsx
Importing in the root
_layout.tsx ensures the CSS is loaded before any of your app screens render, and enables hot reload when you modify styles.Step 3: Configure Metro
Point Metro to your CSS file:metro.config.js
Why This Structure?
- No @source needed: Tailwind scans from the project root, so it automatically finds
appandcomponentsdirectories - Simpler setup: No need to manually configure which directories to scan
- Standard convention: Matches typical React Native project structure
Alternative: App Directory
You can also placeglobal.css inside the app directory:_layout.tsx:app/_layout.tsx
metro.config.js
Global CSS Location Guide
Learn more about configuring global.css
Monorepos & @source
Understand how @source works with multiple directories
Why does my app still fully reload when I change CSS?
Why does my app still fully reload when I change CSS?
If you’re experiencing full app reloads when modifying CSS, even though you followed the documentation and didn’t import Metro can’t efficiently hot reload this file due to the complex provider tree, so any change to
global.css in your root index file, the issue is likely caused by too many Providers in your main App component.The Problem
Metro’s Fast Refresh can’t hot reload components that have too many context providers, state management wrappers, or complex component trees. This is a Metro limitation, not a Uniwind issue.Common scenario:
App.tsx
global.css triggers a full app reload.The Solution
Move theglobal.css import one level deeper to a component that has fewer providers:Option 1: Import in your navigation root
App.tsx
NavigationRoot.tsx
Option 2: Import in your home/main screen
screens/HomeScreen.tsx
Option 3: Import in Expo Router’s nested layout
If using Expo Router, move the import to a nested layout:app/_layout.tsx
app/(tabs)/_layout.tsx
How to Choose Where to Import
Importglobal.css in the deepest component that:- ✅ Is mounted early in your app lifecycle
- ✅ Doesn’t have many providers or complex state
- ✅ Is a good candidate for Fast Refresh
- ✅ Runs on all platforms (iOS, Android, Web)
Testing the Fix
After moving the import:- Restart Metro - Clear cache with
npx expo start --clear - Make a CSS change - Modify a color in
global.css - Check for Fast Refresh - Your app should update without a full reload
If you still see full reloads, try moving the import one level deeper. Some apps with very complex structures may need the import quite deep in the component tree.
Why This Happens
Metro’s Fast Refresh works by:- Detecting which files changed
- Finding components that can be safely updated
- Hot swapping only those components
Fast Refresh Documentation
Learn more about React Native’s Fast Refresh system
How can I use gradients?
How can I use gradients?
Uniwind provides built-in gradient support using Tailwind syntax with React Native’s internal implementation. No additional dependencies required!Available directions:Syntax:
Built-in Gradient Support (Recommended)
Use gradient classes directly with theclassName prop:Directional Gradients
bg-gradient-to-t- Topbg-gradient-to-r- Rightbg-gradient-to-b- Bottombg-gradient-to-l- Leftbg-gradient-to-tr- Top rightbg-gradient-to-br- Bottom rightbg-gradient-to-bl- Bottom leftbg-gradient-to-tl- Top left
Angle-based Gradients
Use specific angles withbg-linear-{angle}:Multi-stop Gradients
Usefrom-, via-, and to- for multiple color stops:Custom Gradients with Arbitrary Values
For complete control, use arbitrary values with custom angles and color stops:bg-linear-[angle,color1_position,color2_position,...]Using expo-linear-gradient
If you need to useexpo-linear-gradient for specific features, you can’t use withUniwind since it doesn’t support mapping props to arrays. Instead, use multiple useCSSVariable calls:❌ This won’t work
✅ Use useCSSVariable instead
Examples
Card with Gradient Background
Button with Gradient
Theme-aware Gradient
How do you handle merging and deduplicating classNames?
How do you handle merging and deduplicating classNames?
Uniwind does not automatically deduplicate classNames, especially on web. When you have conflicting styles or duplicate classes, you’ll need to handle merging manually.
Important: Uniwind doesn’t dedupe classNames. If you pass conflicting styles like
className="bg-red-500 bg-blue-500", both classes will be applied, and the behavior depends on CSS specificity rules.Using tailwind-merge (Recommended)
For proper className merging and deduplication, we recommend usingtailwind-merge with a utility function:Step 1: Install dependencies
Step 2: Create a cn utility
Create a utility file (e.g.,lib/utils.ts or utils/cn.ts):lib/utils.ts
Step 3: Use the cn utility
Now you can merge classNames safely in your components:Why Use tailwind-merge?
Withouttailwind-merge, conflicting classes can cause issues:❌ Without tailwind-merge
✅ With tailwind-merge
Conditional Class Merging
Theclsx library inside cn makes conditional classes easier:How does style specificity work in Uniwind?
How does style specificity work in Uniwind?
Understanding style specificity and priority is important when working with Uniwind to ensure predictable styling behavior.Result: The background will be blue, not red.Result on all platforms: Purple background (inline style always wins)
Inline styles override className
In Uniwind inline styles always have higher priority than className:Platform-specific behavior
Specificity rules work consistently across platforms:Best practices
How to debug 'Failed to serialize javascript object' error?
How to debug 'Failed to serialize javascript object' error?
If you encounter the error “Uniwind Error - Failed to serialize javascript object”, this means Uniwind’s Metro transformer is unable to serialize a complex pattern in your global.css file. This error is specifically about CSS processing, not about classNames in your components.This error appears during the Metro bundling process when Uniwind tries to process your
The Error
global.css file. It can cause your app to fail to build or display a white screen.This error is about CSS patterns in global.css (like complex
@theme configurations, custom properties, or advanced CSS features), not about using className in your components.Debugging Steps
To identify what’s causing the serialization issue, follow these steps:Step 1: Add debug logging
Navigate to the Uniwind Metro transformer file and add a console log to see what’s failing:node_modules/uniwind/dist/metro/metro-transformer.cjs
Step 2: Run your app
After adding the console log, run your Metro bundler:Step 3: Check the output
Look at your Metro terminal output. You should see which object or code pattern is causing the serialization failure.Step 4: Report the issue
Once you’ve identified the problematic code:- Copy the console.log output
- Create a minimal reproduction case if possible
- Report it on GitHub with the output
Include the serialization output and the code pattern causing the issue. This helps the maintainers fix the serializer to support your use case.
Common Causes in global.css
This error is caused by complex patterns in yourglobal.css file that the Metro transformer can’t serialize. Common causes include:- Complex @theme configurations - Very large or deeply nested theme definitions
- Advanced CSS functions - Custom CSS functions or calculations that use JavaScript-like syntax
- Non-standard CSS syntax - Experimental or non-standard CSS features
- Circular references - CSS variables that reference each other in complex ways
Temporary Workarounds
While waiting for a fix:- Simplify your global.css - Break down complex theme configurations into smaller, simpler parts
- Remove experimental features - Comment out advanced CSS features to isolate the issue
Report Serialization Issues
Found a serialization issue? Help improve Uniwind by reporting it
How can I fix Metro unstable_enablePackageExports conflicts?
How can I fix Metro unstable_enablePackageExports conflicts?
Some React Native apps (especially crypto apps) need to disable Uniwind and its dependency (
unstable_enablePackageExports in their Metro configuration. However, Uniwind requires this setting to be enabled to work properly.The Problem
If your Metro config has:metro.config.js
culori) won’t work correctly because they require package exports to be enabled.The Solution
You can selectively enable package exports only for Uniwind and its dependencies while keeping it disabled for everything else:metro.config.js
Why This Works
The customresolveRequest function:- Checks the module name - If it’s
uniwindorculori, it enables package exports - Creates a new context - Temporarily overrides the setting for these specific packages
- Falls back to default - All other packages use the global setting (
false)
When You Need This
Use this solution if:- You’re working with crypto libraries that break with package exports enabled
- You have other dependencies that require
unstable_enablePackageExports = false - You encounter module resolution errors with Uniwind after disabling package exports
If you don’t have any conflicts with
unstable_enablePackageExports, you don’t need this custom resolver. Uniwind works fine with the default Metro configuration.Troubleshooting
If you still encounter issues after adding the custom resolver:- Clear Metro cache - Run
npx expo start --clearornpx react-native start --reset-cache - Rebuild the app - Package export changes may require a full rebuild
- Check the module name - Ensure the module causing issues is included in the
['uniwind', 'culori']array - Verify Metro config - Make sure the custom resolver is defined before calling
withUniwindConfig
Metro Configuration
Learn more about configuring Metro for Uniwind
Does Uniwind work with Vite?
Does Uniwind work with Vite?
Available in Uniwind 1.2.0+Yes. Use Vite with React Native Web, Tailwind, and the Uniwind Vite plugin.
Setup
Createvite.config.ts in your project root:vite.config.ts
Point
cssEntryFile to the CSS file where you import tailwindcss and uniwind. Keep it at your app root for accurate class scanning.How do I enable safe area classNames?
How do I enable safe area classNames?
Available in Uniwind 1.2.0+Install
react-native-safe-area-context and wire safe area insets to Uniwind.Setup
- Add the dependency:
- Wrap your root layout with
SafeAreaListenerand forward insets to Uniwind:
Available classNames
Uniwind provides three categories of safe area utilities:- Padding:
p-safe,pt-safe,pb-safe,pl-safe,pr-safe,px-safe,py-safe - Margin:
m-safe,mt-safe,mb-safe,ml-safe,mr-safe,mx-safe,my-safe - Inset (positioning):
inset-safe,top-safe,bottom-safe,left-safe,right-safe,x-safe,y-safe
or and offset variants:{property}-safe-or-{value}→Math.max(inset, value)- ensures minimum spacing (e.g.,pt-safe-or-4){property}-safe-offset-{value}→inset + value- adds extra spacing on top of inset (e.g.,mb-safe-offset-2)
Class matrix
| Class | Example | Effect |
|---|---|---|
p-safe | className="p-safe" | Sets all padding to the current inset values |
pt-safe | className="pt-safe" | Top padding equals top inset |
m-safe | className="m-safe" | Sets all margins to the inset values |
inset-safe | className="inset-safe" | Sets top/bottom/left/right position to inset values |
top-safe | className="top-safe" | Top position equals top inset |
y-safe | className="y-safe" | Top and bottom positions equal their insets |
pt-safe-or-4 | className="pt-safe-or-4" | Top padding is Math.max(topInset, 16) |
pb-safe-offset-4 | className="pb-safe-offset-4" | Bottom padding is bottomInset + 16 |
top-safe-offset-4 | className="top-safe-offset-4" | Top position is topInset + 16 |
Positioning Examples
Use inset utilities for absolutely positioned elements that need to respect safe areas:Does Uniwind work with Next.js?
Does Uniwind work with Next.js?
Not officially. Uniwind is built for Metro and Vite (via React Native Web), not for Next.js. However, there’s an experimental community-driven plugin that adds Next.js support.
Current Support
Uniwind works out of the box with:- ✅ React Native (Bare workflow)
- ✅ Expo (Managed and bare workflows)
- ✅ Metro bundler (React Native’s default bundler)
- ✅ Vite (with
vite-plugin-rnwanduniwind/vitefor web)
Why Not Next.js?
Next.js uses Webpack (or Turbopack) as its bundler, while Uniwind is architected around Metro’s transformer pipeline. These are fundamentally different build systems with different APIs and plugin architectures.Community Solution
@a16n-dev has createduniwind-plugin-next, a webpack plugin that integrates Uniwind into Next.js applications with SSR support.Official Next.js Support
There is currently no timeline for official Next.js support. While the community plugin works well for many use cases, official support would require significant effort to build and maintain a separate Webpack/Turbopack plugin alongside the Metro architecture.If the community plugin doesn’t meet your needs, consider the alternatives below.Alternatives for Cross-Platform
If the community plugin doesn’t fit your needs:- Use Uniwind for React Native/Expo - For your mobile apps
- Use standard Tailwind CSS for Next.js - For your web app
- Share design tokens - Keep your color palette and spacing consistent via shared configuration
What UI kits work well with Uniwind?
What UI kits work well with Uniwind?
Uniwind works with any React Native component library, but we’ve worked closely with UI kit teams to ensure the best integration and performance.
Recommended UI Kits
React Native Reusables
shadcn/ui for React Native - beautifully crafted components
HeroUI Native
Beautiful, fast and modern React Native UI library
React Native Reusables - shadcn for React Native
React Native Reusables brings the beloved shadcn/ui philosophy to React Native. Built with Uniwind (or NativeWind), it provides beautifully designed, accessible, and customizable components that you can copy and paste into your apps.Why React Native Reusables?- 🎨 shadcn Philosophy - Copy, paste, and own your components. No package bloat
- ✅ Uniwind Native - Built specifically for Uniwind with full className support
- 🎯 Beautifully Crafted - Premium design inspired by shadcn/ui’s aesthetics
- ♿ Accessible - WCAG-compliant components that work across all platforms
- 🎛️ Fully Customizable - Modify components to match your exact design requirements
- 📱 React Native First - Designed for mobile, works perfectly on iOS, Android, and web
HeroUI Native - Complete Component Library
HeroUI Native is a comprehensive, production-ready React Native UI library. It’s built for speed, accessibility, and seamless integration with Uniwind.Why HeroUI Native?- ✅ Built for Uniwind - Designed to work seamlessly with Uniwind’s styling system
- ✅ Optimized Performance - Collaborated closely with the HeroUI team for best-in-class performance
- ✅ Accessible - ARIA-compliant components that work on all platforms
- ✅ Extensive Theming - Deep integration with Uniwind’s theme system
- ✅ Modern Design - Beautiful, contemporary components out of the box
- ✅ Comprehensive - Full set of components for building production apps
Both UI kits work seamlessly with Uniwind’s
className prop and support all Tailwind utilities out of the box. Choose based on your preferred workflow: copy-paste (Reusables) or npm install (HeroUI).More UI Kits Coming
We’re actively working with other UI library teams to bring first-class Uniwind support to more component libraries. Stay tuned for announcements!Using Other Component Libraries
Uniwind works with any React Native component library. For libraries that don’t natively supportclassName, you can use withUniwind to add className support:withUniwind API
Learn how to add className support to any component
Third-party Components
See examples of using Uniwind with various component libraries