NativeWindは、React Nativeのコンポーネントに className="p-4 bg-white" のようなTailwind CSSのクラスを書けるようにするライブラリです。2026年10月時点の安定版は4.2.7で、組み合わせるTailwind CSSはv3系に限られます。Tailwind CSS v4に対応するv5は、2026年9月13日に5.0.0-rc.0(リリース候補)が出た段階です。
この記事では、NativeWind 4.2.7をローカルに入れて、クラスがiOS・Android向けのスタイルにどう変換されるかを実際にコンパイルして確かめた結果をもとに、導入手順と「Webでは効くのにアプリでは効かないクラス」を整理します。検証したのはクラスからネイティブ向けスタイルへの変換結果までで、実機での描画は確認していません。版と手順は公式のInstallationと5.0.0-rc.0のリリースノートに基づきます。
まとめ:NativeWindの要点(2026年10月時点)
- 何をするか:ビルド時にTailwindのクラスを
StyleSheet.create相当のオブジェクトへ変換し、実行時にダークモードや画面幅などの条件を当てはめる。Webでは通常のCSSを使う。 - 版:安定版は4.2.7(2026年9月14日・Tailwind CSS v3)。v5は5.0.0-rc.0(Tailwind CSS v4)で、公式は本番利用を想定しないと明記している。
- Tailwind v4は入れない:4.2.7にtailwindcss 4.3.3を入れると、Metro設定の読み込み時点で「NativeWind only supports Tailwind CSS v3」で止まる。
- 効かないクラスがある:
grid・fixed・sticky・blur-*・グラデーション・space-y-*はネイティブでは捨てられる。エラーは出ない。 - 数値はWebと違う:ネイティブの1remは14として計算されるので、
p-4は16ではなく14になる。
NativeWindの仕組み:classNameがネイティブのスタイルになるまで
React NativeにはCSSエンジンがありません。View や Text が受け取るのは style に渡すJavaScriptのオブジェクトだけです。NativeWindはこの隙間を2段階で埋めます。
1段目はビルド時の変換です。Metroの起動時にTailwind CLIでCSSを生成し、それを react-native-css-interop(4.2.7が依存する変換エンジン・0.2.7)がReact Nativeのスタイルオブジェクトへ変換します。2段目は実行時の処理で、dark:・md:・active: などの条件付きスタイルを、端末の状態に合わせてその場で選びます。className はJSX変換(Babelの jsxImportSource)で各コンポーネントに渡るので、ラッパー部品を作る必要はありません。
Webでは動きが変わります。React Native Webで描画する場合、NativeWindはスタイルを変換せず、Tailwindが出力したCSSファイルをそのまま使います。Web版の描画の仕組みはReact Native WebのDOM変換の仕組みで詳しく扱っています。
v4.2.7とv5 RCの違いと選び方
「nativewind v4」「nativewind v5」「nativewind tailwind v4」で検索する人が迷うのは、NativeWindの版番号とTailwind CSSの版番号が1つずれている点です。NativeWind v4が使うのはTailwind v3で、Tailwind v4を使うのはNativeWind v5です。
| 項目 | NativeWind 4.2.7(安定版) | NativeWind 5.0.0-rc.0 |
|---|---|---|
| npmの配布タグ | latest | preview / rc |
| 公開日 | 2026-09-14 | 2026-09-13 |
| Tailwind CSS | v3(3.4.17以上を推奨) | v4(4.1.12で固定) |
| 変換エンジン | react-native-css-interop 0.2.7 | react-native-css 3.1.0-rc.0 |
| 設定の書き方 | tailwind.config.js | CSSの @import / @theme |
| Babel | nativewind/babel が必要 |
不要(Expoのpresetのみ) |
| Metro | withNativeWind(config, { input }) |
withNativewind(config) |
| 対応・検証済みのExpo | SDK 57に対応 | Expo 57.0.22 |
Tailwind CSS本体のv3とv4の差(設定のCSS化、shadow-sm などの名称変更)はTailwind CSS v3とv4の違いで実ビルドの結果つきで整理しています。NativeWindの版を選ぶときも、この差がそのまま設定ファイルの書き換え量になります。
Tailwind CSS v4を入れたときに4.2.7が止まる箇所
4.2.7の package.json はTailwindの条件を >3.3.0 と書いているので、表面上はv4も通るように見えます。実際の挙動を確かめるため、Node v26.5.0・npm 11.17.0の空のプロジェクトで2通り試しました。
# 版を指定せずに入れる
npm install nativewind tailwindcss
# → nativewind 4.2.7 / tailwindcss 3.4.19 が入る
# Tailwind v4を明示して入れ直す
npm install [email protected]
# → npm warn ERESOLVE overriding peer dependency
# → metro.config.js の withNativeWind() 実行時に
# Error: NativeWind only supports Tailwind CSS v3
版を指定しなければ、依存先の react-native-css-interop がTailwindを ~3 に縛っているため、npmは3.4.19を選びます。v4を明示した場合だけ警告が出て、Metroの起動時に止まります。公式の手順どおり tailwindcss@^3.4.17 と書いておけば、この事故は起きません。
v5 RCへ移る判断基準
既存のアプリは、v5の正式版が出るまで4.2.7のままにするのが妥当です。v5のドキュメントは冒頭で「本番利用を意図していない」と書いており、RCのリリースノートも、正式版への昇格をRCのフィードバックと移行手順の検証が終わった後としています。日付は示されていません。
v5を試す価値があるのは、Web側ですでにTailwind v4のテーマ(@theme)を持っていて、アプリと同じトークンを共有したい場合です。移行では次の作業が必要になります。
tailwind.config.jsをTailwind v4のCSS設定へ書き換える- Babel設定から
nativewind/babelとjsxImportSourceを外す(babel-preset-expoは残す) - Metroの関数を
withNativewindに替える(wが小文字になる) - CSS内の
@cssInterop指令と、ネイティブでの:root.darkはエラーになるので書き換える
RC時点の既知の問題として、Androidで回転アニメーションを取り消しても最後の変形が残る不具合が挙がっています。原因はReanimated側(issue 10507)とされ、NativeWindを使わない直接の実装でも再現すると書かれています。
Expoへの導入手順(NativeWind 4.2.7)
新規プロジェクトなら、公式が案内する npx rn-new --nativewind でNativeWind入りのExpoプロジェクトを作れます。既存のExpoプロジェクトに入れる場合は、次の6か所を設定します。
npx expo install [email protected] react-native-reanimated react-native-safe-area-context
npx expo install --dev tailwindcss@^3.4.17 prettier-plugin-tailwindcss@^0.5.11 babel-preset-expo
# Expo SDK 57 で Reanimated 4 を使う場合は worklets も入れる
npx expo install react-native-worklets
react-native-reanimated は、NativeWindのトランジションとアニメーション用クラスが使います。Reanimated 4系は react-native-worklets を別途必要とします。4.2.7はReanimated 3と4の両方に対応しているので、Reanimated 3の古い構成にworkletsを足す必要はありません。版の縛りはReact Native Reanimatedの4系の版の縛りで整理しています。
// tailwind.config.js
module.exports = {
content: ["./app/**/*.{js,jsx,ts,tsx}", "./components/**/*.{js,jsx,ts,tsx}"],
presets: [require("nativewind/preset")],
theme: { extend: {} },
plugins: [],
};
content にはクラスを書くファイルをすべて含めます。Expo Routerなら app フォルダが漏れやすい箇所です。presets の nativewind/preset を外すと、Metroの起動時に「Tailwind CSS has not been configured with the NativeWind preset」で止まります。
/* global.css */
@tailwind base;
@tailwind components;
@tailwind utilities;
// babel.config.js
module.exports = function (api) {
api.cache(true);
return {
presets: [
["babel-preset-expo", { jsxImportSource: "nativewind" }],
"nativewind/babel",
],
};
};
// metro.config.js
const { getDefaultConfig } = require("expo/metro-config");
const { withNativeWind } = require("nativewind/metro");
const config = getDefaultConfig(__dirname);
module.exports = withNativeWind(config, { input: "./global.css" });
最後に、ルートのレイアウト(Expo Routerなら app/_layout.tsx)で import "../global.css"; を1回だけ書きます。Webにも出すなら app.json の expo.web.bundler を "metro" にします。TypeScriptでは nativewind-env.d.ts に /// <reference types="nativewind/types" /> を書きます。このファイルを nativewind.d.ts と名付けると型が読み込まれないと公式が注意しています。
React Native CLI(Expoなし)の差分
Expoを使わない構成でも手順はほぼ同じです。違いは3点で、npx pod-install でReanimatedのiOS側を入れること、Babelは既存のpresetに nativewind/babel を足すだけであること、Metroの設定を @react-native/metro-config の mergeConfig で組むことです。Webに出す場合、Expoを使わないならExpoのMetro設定を借りるか、Tailwind CLIでCSSを別途生成する必要があります。
導入できたかを確かめる手順
公式の切り分けは「まずTailwind単体でCSSが出るか」から始まります。npx tailwindcss --input ./global.css --output output.css を実行し、使いたいクラスが output.css に出ていなければTailwind側(content の漏れやクラス名の誤記など)の問題です。出ていればNativeWind側を疑います。import { verifyInstallation } from "nativewind"; を追加し、Reactコンポーネント内で verifyInstallation() を呼ぶと、導入状態を検査できます。設定を変えたあとは npx expo start --clear でキャッシュを消してから見ます。
Tailwind CSSとの違い:ネイティブで効くクラス・効かないクラス
NativeWindはどのクラスも受け付けますが、ネイティブで表現できないスタイルは黙って捨てます。どれが捨てられるかを確かめるため、4.2.7で約50個のクラスをiOS・Android向けにコンパイルしました。withNativeWind と同じ経路(Tailwind CLI→cssToReactNativeRuntime、rem=14)を使っています。
| クラス | iOSの出力 | Androidの出力 |
|---|---|---|
| p-4 | padding: 14 | padding: 14 |
| text-base | fontSize 14 / lineHeight 21 | 同左 |
| rounded-lg | borderRadius: 7 | 同左 |
| w-[37px] | width: 37 | 同左 |
| bg-blue-500/50 | #3b82f680(固定値) | 同左 |
| shadow-md | shadowOffset 0,3 / radius 10 | 上記+elevation: 6 |
| line-clamp-2 | numberOfLines: 2 | 同左 |
| truncate | overflow: hidden のみ | 同左 |
| grid / grid-cols-2 | 破棄 | 破棄 |
| fixed / sticky | 破棄 | 破棄 |
| blur-sm / backdrop-blur-sm | 破棄 | 破棄 |
| bg-gradient-to-r | 破棄 | 破棄 |
| space-y-4 / divide-y | 出力なし | 出力なし |
| cursor-pointer | 破棄 | 破棄 |
「破棄」は、コンパイラが警告(IncompatibleNativeValue または IncompatibleNativeProperty)を残してスタイルを空にしたものです。アプリはエラーにならず、見た目だけが変わらないので、気づくのは画面を開いたときになります。
grid・space-y・グラデーションの代替
「nativewind grid」で探しても、ネイティブで grid を有効にする設定はありません。公式の互換表でも grid と grid-cols-* はWeb専用です。2列のカード一覧は、Flexboxの折り返しで組みます。
<View className="flex-row flex-wrap">
{items.map((item) => (
<View key={item.id} className="w-1/2 p-2">
<Card item={item} />
</View>
))}
</View>
w-1/2 は width: "50%" に変換されます。列の間隔を gap-* で取ると50%+50%+間隔が100%を超えて1列に落ちるので、間隔は子の p-2 で取ります。要素の間隔をあける space-y-* は、NativeWind v4で一時的に外されたと公式が明記しており、代わりに親へ gap-* を付けます。グラデーションは expo-linear-gradient などの部品を使います。
remの既定値:ネイティブ14とWeb16の差
React Nativeの Text は既定の文字サイズが14です。NativeWindはこれに合わせ、ネイティブでは1rem=14、Webでは1rem=16として計算します。実測でも p-4 は14、m-2 は7、text-xl は17.5でした。Webのデザインカンプと数値をそろえたい場合は、ネイティブでは数値が物理ピクセルではなく密度非依存の単位として扱われる点を踏まえ、withNativeWind の第2引数で inlineRem: 16 を渡すか、w-[37px] のように単位付きの任意値で書きます。任意値はそのまま width: 37 になり、ネイティブではこれが37dpとして描画されます。
shadowの変換結果とAndroidのelevation値
shadow-md はiOSでは shadowOffset・shadowRadius・shadowColor に、Androidではそれに加えて elevation: 6 に変換されました。shadow-sm は1、shadow は3、shadow-lg は8、shadow-xl は13です。Androidでは主にelevationで影を表現し、対応OSではshadowColorも反映されます。shadowOffset・shadowOpacity・shadowRadiusはiOS専用なので、コンパイル結果に含まれていてもAndroidでは同じ効果になりません。公式は「背景色を指定しないとネイティブで影が出ないことがある」とも注意しているので、影を付ける要素には bg-white などを必ず付けます。
ViewとTextの文字色継承の制約
Webでは親の text-red-500 が子の文字に継承されますが、React Nativeの View は color を受け取らず、子にも伝えません。文字色・文字サイズのクラスは Text に直接付けます。truncate は前述のとおり overflow: hidden しか残らないので、1行で省略したいときは line-clamp-1 を使います。これは Text の numberOfLines に変換されます。
ダークモード・端末別・状態のバリアント
dark:bg-black は prefers-color-scheme: dark の条件付きスタイルに変換され、端末の外観設定に追従します。Expoでは app.json の userInterfaceStyle を "automatic" に設定します。Androidの開発ビルドでは npx expo install expo-system-ui で依存パッケージも追加し、ネイティブ設定を変更したらアプリを再ビルドします。アプリ内のトグルで切り替えるなら、nativewind から読み込む colorScheme.set("dark") を使います。
公式が勧めるのは、dark:text-white だけを書くのではなく、text-black dark:text-white のように両方の状態を明示する書き方です。React Nativeは条件付きでスタイルを外す処理に弱く、片側だけだと切り替え時に色が残ることがあります。
端末別のバリアントは ios:・android:・web:・native:(Web以外すべて)・windows:・osx: の6つです。OSごとに上余白を変える例は ios:pt-12 android:pt-6 です。ただし、固定余白では機種や向きで変わるノッチ領域に対応できないため、ノッチ対策には react-native-safe-area-context の実際のInsetsを使います。md: などの画面幅バリアントも動きますが、区切り(md=768)はWeb向けのままで、公式も「既定のテーマはまだネイティブ向けに設計されていない」と書いています。
hover:・active:・focus: は、そのイベントを持つ部品でだけ効きます。active:opacity-50 を押下時に効かせたいなら、View ではなく Pressable に付けます。
サードパーティ部品にclassNameを通す:cssInteropとremapProps
サードパーティ部品でも、受け取った className をReact Nativeの基本コンポーネントへ転送していれば、そのままスタイルが当たります。どの部品が転送しているかはソースを見ないと分からないと公式も書いています。転送しない部品や、style ではなく独自のpropでスタイルを受ける部品には、対応表を渡す必要があります。FlatList の contentContainerStyle や、buttonStyle・labelStyle を持つボタンが典型です。
import { remapProps, cssInterop } from "nativewind";
import { Svg, Circle } from "react-native-svg";
// 独自のstyle系propへclassNameを割り当てる
const CustomButton = remapProps(ThirdPartyButton, {
buttonClassName: "buttonStyle",
labelClassName: "labelStyle",
});
// fill・strokeをstyleでなくpropとして受けるSVG部品
const StyledCircle = cssInterop(Circle, {
className: {
target: "style",
nativeStyleToProp: { fill: true, stroke: true, strokeWidth: true },
},
});
remapProps は新しいprop名と既存のstyle系propを対応させるだけの軽い関数です。cssInterop は、スタイルの一部を fill のような別propへ移す必要があるときに使います。v5 RCではNativeWindからの両APIの公開がなくなり、nativewind の styled で対応するラッパーを作り、その戻り値を描画します。多用しているアプリでは、propの対応関係も個別に検証します。
StyleSheet・twrnc・Uniwindとの比較と選び方
React NativeでTailwindのクラスを使う方法は、NativeWindのほかにも複数あります。週間ダウンロード数は、npm公式のダウンロード統計API(api.npmjs.org)で取得した2026年9月24日〜30日の値です。
| 方式 | 最新版 | Tailwind | 書き方 | 週間DL |
|---|---|---|---|---|
| NativeWind | 4.2.7 | v3 | className | 約210万 |
| Uniwind | 1.12.1 | v4以上 | className | 約107万 |
| twrnc | 4.16.0 | 独自実装 | style={tw.style("p-4")} |
約8万 |
| StyleSheet | React Native標準 | なし | style={styles.box} |
(標準機能) |
判断は次の順で決まります。Tailwind v3の設定やWebとの共通部品をすでに持っているなら、Tailwind v3を継続して使えるNativeWind 4.2.7が移行作業を抑えやすい選択です。新規でTailwind v4のテーマから始めるなら、NativeWind v5の正式版を待つか、Tailwind v4を前提に作られたUniwind(React 19以上・React Native 0.81以上が必要)を選びます。Uniwindの特徴はUniwindとは何かで解説しています。Babel・Metroの設定に手を入れたくない場合は、関数でクラス文字列をstyleオブジェクトに変えるtwrncが手軽です。
NativeWindを選ぶべきでないのは、デザインがCSS Gridやぼかし・グラデーションに大きく依存している場合です。上の実測のとおり、これらはネイティブで捨てられるので、クラスをそのまま移植しても再現できず、結局StyleSheetや専用部品で書き直すことになります。画面数が少なく、Web側のTailwind資産もないアプリなら、標準のStyleSheetで足ります。
classNameが効かないときの確認順
- キャッシュを消して再起動:
npx expo start --clear(Expoなしならnpx react-native start --reset-cache)。古いキャッシュの影響を除いてから、後続の項目を確認する。 - Tailwind単体でクラスが出るか:
npx tailwindcss --input ./global.css --output output.cssで対象クラスを探す。出ていなければ、contentのパス漏れ、クラス名の誤記、動的な文字列連結、テーマ設定を確認する。 - global.cssを読み込んでいるか:ルートのレイアウトで1回だけ
importしているかを見る。 - Babel・Metroの設定:
jsxImportSource: "nativewind"・nativewind/babel・withNativeWindの3点がそろっているか。 - そのクラスがネイティブで有効か:前章の表と公式の互換表で、Web専用のクラスでないかを確認する。
- 付けた部品がそのスタイルを受け取るか:
Viewに文字色、onHoverのない部品にhover:を付けていないか。
それでも原因が分からない場合は、DEBUG=nativewind npx expo start --clear で起動すると、NativeWindが処理の経過を端末に出力します。公式は、この出力が不具合を報告するときに役立つと説明しています。
よくある質問
NativeWindはTailwind CSS v4で使えますか?
安定版の4.2.7では使えません。tailwindcss 4.3.3を入れると、Metroの起動時に「NativeWind only supports Tailwind CSS v3」で止まります。Tailwind v4に対応しているのは5.0.0-rc.0(2026年9月13日公開のリリース候補)で、公式は本番利用を想定しないとしています。
NativeWindでgridは使えますか?
ネイティブでは使えません。grid と grid-cols-* はコンパイル時に破棄され、エラーも出ません。Webでのみ有効です。アプリでは flex-row flex-wrap と w-1/2 などの幅指定で並べます。
NativeWind UIとNativeWindの違いは何ですか?
NativeWindはスタイルの仕組みで、NativewindUI(nativewindui.com)はNativeWindの上に作られたUI部品とテンプレートの集合です。公式サイトは「NativeWindとReact Native Reusablesの作者による」と紹介しており、iOS・Androidそれぞれの見た目に合わせた30以上の部品とテンプレートを提供しています。NativeWindだけでは部品は付いてきません。
shadcn/uiをReact Nativeで使えますか?
shadcn/ui本体はWeb向けですが、同じ考え方をReact Nativeへ移したReact Native Reusables(GitHub: founded-labs/react-native-reusables)があります。NativeWindまたはUniwindでスタイルを当てる部品群です。
NativeWind v5の正式版はいつ出ますか?
日付は公表されていません。5.0.0-rc.0のリリースノートは、正式版への昇格条件を「RCへの利用者フィードバック」と「v4からv5への移行手順を代表的なアプリで検証すること」としています。それまでnpmの latest タグは4系のままです。