U

uniwind

by @uni-stackv
4.3(37)

Tailwind CSS v4スタイルをReact Nativeプロジェクトに適用し、クロスプラットフォームで統一されたデザインを実現し、開発効率を向上させます。

css-frameworkstailwind-cssutility-first-cssfrontend-developmentresponsive-designGitHub
インストール方法
npx skills add uni-stack/uniwind --skill uniwind
compare_arrows

Before / After 効果比較

1
使用前

React Nativeで複雑なUIスタイルを実装するには、通常、大量のCSS-in-JSまたはStyleSheetオブジェクトを記述する必要があり、スタイルコードが冗長で保守が困難になり、統一されたデザインシステムが不足し、開発効率が制限されていました。

使用後

UniwindはTailwind CSS v4の強力な機能をReact Nativeにもたらし、開発者がアトミックな方法で美しいUIを迅速に構築できるようにします。これにより、スタイル記述が大幅に簡素化され、開発速度が向上し、クロスプラットフォームでの視覚的な一貫性が確保されます。

SKILL.md

Uniwind — Complete Reference

Uniwind 1.5.0+ / Tailwind CSS v4 / React Native 0.81+ / Expo SDK 54+

If user has lower version, recommend updating to 1.5.0+ for best experience.

Uniwind brings Tailwind CSS v4 to React Native. All core React Native components support the className prop out of the box. Styles are compiled at build time — no runtime overhead.

Critical Rules

  1. Tailwind v4 only — Use @import 'tailwindcss' not @tailwind base. Tailwind v3 is not supported.
  2. Never construct classNames dynamically — Tailwind scans at build time. bg-${color}-500 will NOT work. Use complete string literals, mapping objects, or ternaries.
  3. Never use cssInterop or remapProps — Those are NativeWind APIs. Uniwind does not override global components.
  4. No tailwind.config.js — All config goes in global.css via @theme and @layer theme.
  5. No ThemeProvider required — Use Uniwind.setTheme() directly.
  6. withUniwindConfig must be the outermost Metro config wrapper.
  7. NEVER wrap react-native or react-native-reanimated components with withUniwindView, Text, Pressable, Image, TextInput, ScrollView, FlatList, Switch, Modal, Animated.View, Animated.Text, etc. already have full className support built in. Wrapping them with withUniwind will break behavior. Only use withUniwind for third-party components (e.g., expo-image, expo-blur, moti).
  8. Font families: single font only — React Native doesn't support fallbacks. Use --font-sans: 'Roboto-Regular' not 'Roboto', sans-serif.
  9. All theme variants must define the same set of CSS variables — If light defines --color-primary, then dark and every custom theme must too. Mismatched variables cause runtime errors.
  10. accent- prefix is REQUIRED for non-style color props — This is crucial. Props like color (Button, ActivityIndicator), tintColor (Image), thumbColor (Switch), placeholderTextColor (TextInput) are NOT part of the style object. You MUST use the corresponding {propName}ClassName prop with accent- prefixed classes. Example: <ActivityIndicator colorClassName="accent-blue-500" /> NOT <ActivityIndicator className="text-blue-500" />. Regular Tailwind color classes (like text-blue-500) only work on className (which maps to style). For non-style color props, always use accent-.
  11. rem default is 16px — NativeWind used 14px. Set polyfills: { rem: 14 } in metro config if migrating.
  12. cssEntryFile must be a relative path string — Use './global.css' not path.resolve(__dirname, 'global.css').
  13. Deduplicate with cn() when mixing custom CSS classes and Tailwind — Uniwind does NOT auto-deduplicate. If a custom CSS class (.card { padding: 16px }) and a Tailwind utility (p-6) set the same property, both apply with unpredictable results. Always wrap with cn('card', 'p-6') when there's overlap.

Setup

Installation

# or other package manager
bun install uniwind tailwindcss

Requires Tailwind CSS v4+.

global.css

Create a CSS entry file:

@import 'tailwindcss';
@import 'uniwind';

Import in your App component (e.g., App.tsx or app/_layout.tsx), NOT in index.ts/index.js — importing there breaks hot reload:

// app/_layout.tsx or App.tsx
import './global.css';

The directory containing global.css is the app root — Tailwind scans for classNames starting from this directory.

Metro Configuration

const { getDefaultConfig } = require('expo/metro-config');
// Bare RN: const { getDefaultConfig } = require('@react-native/metro-config');
const { withUniwindConfig } = require('uniwind/metro');

const config = getDefaultConfig(__dirname);

// withUniwindConfig MUST be the OUTERMOST wrapper
module.exports = withUniwindConfig(config, {
  cssEntryFile: './global.css',           // Required — relative path from project root
  polyfills: { rem: 16 },                // Optional — base rem value (default 16)
  extraThemes: ['ocean', 'sunset'],       // Optional — custom themes beyond light/dark
  dtsFile: './uniwind-types.d.ts',        // Optional — TypeScript types output path
  debug: true,                            // Optional — log unsupported CSS in dev
  isTV: false,                            // Optional — enable TV platform support
});

For most flows, keep defaults, only provide cssEntryFile.

Wrapper order — Uniwind must wrap everything else:

// CORRECT
module.exports = withUniwindConfig(withOtherConfig(config, opts), { cssEntryFile: './global.css' });

// WRONG — Uniwind is NOT outermost
module.exports = withOtherConfig(withUniwindConfig(config, { cssEntryFile: './global.css' }), opts);

Vite Configuration (v1.2.0+)

If user has storybook setup, add extra vite config:

import tailwindcss from '@tailwindcss/vite';
import { uniwind } from 'uniwind/vite';
import { defineConfig } from 'vite';

export default defineConfig({
  plugins: [
    tailwindcss(),
    uniwind({
      cssEntryFile: './src/global.css',
      dtsFile: './src/uniwind-types.d.ts',
    }),
  ],
});

TypeScript

Uniwind auto-generates a .d.ts file (default: ./uniwind-types.d.ts) after running Metro. Place it in src/ or app/ for auto-inclusion, or add to tsconfig.json:

{ "include": ["./uniwind-types.d.ts"] }

If user has some typescript errors related to classNames, just run metro server to build the d.ts file.

Expo Router Placement

project/
├── app/_layout.tsx    ← import '../global.css' here
├── components/
├── global.css         ← project root (best location)
└── metro.config.js    ← cssEntryFile: './global.css'

If global.css is in app/ dir, add @source for sibling directories:

@import 'tailwindcss';
@import 'uniwind';
@source '../components';

Tailwind IntelliSense (VS Code / Cursor / Windsurf)

{
  "tailwindCSS.classAttributes": [
    "class", "className", "headerClassName",
    "contentContainerClassName", "columnWrapperClassName",
    "endFillColorClassName", "imageClassName", "tintColorClassName",
    "ios_backgroundColorClassName", "thumbColorClassName",
    "trackColorOnClassName", "trackColorOffClassName",
    "selectionColorClassName", "cursorColorClassName",
    "underlineColorAndroidClassName", "placeholderTextColorClassName",
    "selectionHandleColorClassName", "colorsClassName",
    "progressBackgroundColorClassName", "titleColorClassName",
    "underlayColorClassName", "colorClassName",
    "backdropColorClassName", "backgroundColorClassName",
    "statusBarBackgroundColorClassName", "drawerBackgroundColorClassName",
    "ListFooterComponentClassName", "ListHeaderComponentClassName"
  ],
  "tailwindCSS.classFunctions": ["useResolveClassNames"]
}

Monorepo Support

Add @source directives in global.css for packages outside the CSS entry file's directory:

@import 'tailwindcss';
@import 'uniwind';
@source "../../packages/ui/src";
@source "../../packages/shared/src";

Also needed for node_modules packages that contain Uniwind classes (e.g., shared UI libraries).

Component Bindings

All core React Native components support className out of the box. Some have additional className props for sub-styles (like contentContainerClassName) and non-style color props (requiring accent- prefix).

Complete Reference

Legend: Props marked with ⚡ require the accent- prefix. Props in parentheses are platform-specific.

View

PropMaps toPrefix
classNamestyle

Text

PropMaps toPrefix
classNamestyle
selectionColorClassNameselectionColoraccent-

Pressable

PropMaps toPrefix
classNamestyle

Supports active:, disabled:, focus: state selectors.

Image

PropMaps toPrefix
classNamestyle
tintColorClassNametintColoraccent-

TextInput

PropMaps toPrefix
classNamestyle
cursorColorClassNamecursorColoraccent-
selectionColorClassNameselectionColoraccent-
placeholderTextColorClassNameplaceholderTextColoraccent-
selectionHandleColorClassNameselectionHandleColoraccent-
underlineColorAndroidClassNameunderlineColorAndroid (Android)accent-

Supports focus:, active:, disabled: state selectors.

ScrollView

PropMaps toPrefix
classNamestyle
contentContainerClassNamecontentContainerStyle
endFillColorClassNameendFillColoraccent-

FlatList

PropMaps toPrefix
classNamestyle
contentContainerClassNamecontentContainerStyle
columnWrapperClassNamecolumnWrapperStyle
ListHeaderComponentClassNameListHeaderComponentStyle
ListFooterComponentClassNameListFooterComponentStyle
endFillColorClassNameendFillColoraccent-

SectionList

PropMaps toPrefix
classNamestyle
contentContainerClassNamecontentContainerStyle
ListHeaderComponentClassNameListHeaderComponentStyle
ListFooterComponentClassNameListFooterComponentStyle
endFillColorClassNameendFillColoraccent-

VirtualizedList

PropMaps toPrefix
classNamestyle
contentContainerClassNamecontentContainerStyle
ListHeaderComponentClassNameListHeaderComponentStyle
ListFooterComponentClassNameListFooterComponentStyle
endFillColorClassNameendFillColoraccent-

Switch

PropMaps toPrefix
thumbColorClassNamethumbColoraccent-
trackColorOnClassNametrackColor.true (on)accent-
trackColorOffClassNametrackColor.false (off)accent-
ios_backgroundColorClassNameios_backgroundColor (iOS)accent-

Note: Switch does NOT support className (className?: never in types). Use only the color-specific className props above. Supports disabled: state selector.

ActivityIndicator

PropMaps toPrefix
classNamestyle
colorClassNamecoloraccent-

Button

PropMaps toPrefix
colorClassNamecoloraccent-

Note: Button does not support className (no style prop on RN Button).

Modal

PropMaps toPrefix
classNamestyle
backdropColorClassNamebackdropColoraccent-

RefreshControl

PropMaps toPrefix
classNamestyle
colorsClassNamecolors (Android)accent-
tintColorClassNametintColor (iOS)accent-
titleColorClassNametitleColor (iOS)accent-
progressBackgroundColorClassNameprogressBackgroundColor (Android)accent-

ImageBackground

PropMaps toPrefix
classNamestyle
imageClassNameimageStyle
tintColorClassNametintColoraccent-

SafeAreaView

PropMaps toPrefix
classNamestyle

KeyboardAvoidingView

PropMaps toPrefix
classNamestyle
contentContainerClassNamecontentContainerStyle

InputAccessoryView

PropMaps toPrefix
classNamestyle
backgroundColorClassNamebackgroundColoraccent-

TouchableHighlight

PropMaps toPrefix
classNamestyle
underlayColorClassNameunderlayColoraccent-

Supports active:, disabled: state selectors.

TouchableOpacity

PropMaps toPrefix
classNamestyle

Supports active:, disabled: state selectors.

TouchableNativeFeedback

PropMaps toPrefix
classNamestyle

Supports active:, disabled: state selectors.

TouchableWithoutFeedback

PropMaps toPrefix
classNamestyle

Supports active:, disabled: state selectors.

Usage Examples

import { View, Text, Pressable, TextInput, ScrollView, FlatList, Switch, Image, ActivityIndicator, Modal, RefreshControl, Button } from 'react-native';

// View — basic layout
<View className="flex-1 bg-background p-4">
  <Text className="text-foreground text-lg font-bold">Title</Text>
</View>

// Pressable — with press/focus states
<Pressable className="bg-primary px-6 py-3 rounded-lg active:opacity-80 active:bg-primary/90 focus:ring-2">
  <Text className="text-white text-center font-semibold">Press Me</Text>
</Pressable>

// TextInput — with focus state and accent- color props
<TextInput
  className="border border-border rounded-lg px-4 py-2 text-base text-foreground focus:border-primary"
  placeholderTextColorClassName="accent-muted"
  selectionColorClassName="accent-primary"
  cursorColorClassName="accent-primary"
  selectionHandleColorClassName="accent-primary"
  underlineColorAndroidClassName="accent-transparent"
  placeholder="Enter text..."
/>

// ScrollView — with content container
<ScrollView className="flex-1" contentContainerClassName="p-4 gap-4">
  {/* content */}
</ScrollView>

// FlatList — with all sub-style props
<FlatList
  className="flex-1"
  contentContainerClassName="p-4 gap-3"
  columnWrapperClassName="gap-3"
  ListHeaderComponentClassName="pb-4"
  ListFooterComponentClassName="pt-4"
  endFillColorClassName="accent-gray-100"
  numColumns={2}
  data={items}
  renderItem={({ item }) => <ItemCard item={item} />}
/>

// Switch — no className support, use color-specific props only
<Switch
  thumbColorClassName="accent-white"
  trackColorOnClassName="accent-primary"
  trackColorOffClassName="accent-gray-300 dark:accent-gray-700"
  ios_backgroundColorClassName="accent-gray-200"
/>

// Image — tint color
<Image className="w-6 h-6" tintColorClassName="accent-primary" source={icon} />

// ActivityIndicator
<ActivityIndicator className="m-4" colorClassName="accent-primary" size="large" />

// Button — only colorClassName (no className)
<Button colorClassName="accent-primary" title="Submit" onPress={handleSubmit} />

// Modal — backdrop color
<Modal className="flex-1" backdropColorClassName="accent-black/50">
  {/* content */}
</Modal>

// RefreshControl

...

ユーザーレビュー (0)

レビューを書く

効果
使いやすさ
ドキュメント
互換性

レビューなし

統計データ

インストール数2.0K
評価4.3 / 5.0
バージョン
更新日2026年5月21日
比較事例1 件

ユーザー評価

4.3(37)
5
70%
4
30%
3
0%
2
0%
1
0%

この Skill を評価

0.0

対応プラットフォーム

🔧Claude Code
🔧OpenClaw
🔧OpenCode
🔧Codex
🔧Gemini CLI
🔧GitHub Copilot
🔧Amp
🔧Kimi CLI

タイムライン

作成2026年3月16日
最終更新2026年5月21日