📱

モバイルアプリ開発でもTailwindを使いたい人へ - React Native + expoにNativeWindを導入する方法

はじめに

React Nativeを使ってアプリ開発をする際、スタイリングは使い慣れているTailwind CSSを使いたい人もいるかと思います。そんな時、NativeWindというライブラリを使えば、React NativeプロジェクトでもTailwind CSSが使えるようになります。

今回はExpoのプロジェクトにNativeWindを導入し、使えるまでの流れを紹介します。

対象読者

  • 普段はWebの環境で開発している方
  • ReactやTailwind CSSの経験者
  • モバイルアプリ開発が未経験の方

NativeWind とは

NativeWindは比較的新しいライブラリで、React Nativeのために、Tailwind CSSのスタイリング手法を利用できるライブラリとして2022年に開発されました(initial commitは2022年4月頃)。

目的は、Webとモバイルアプリの開発で統一されたスタイリング体験を提供し、開発を効率化することかと思います。

https://www.nativewind.dev/

React Native と Expo とは

React Nativeは、iOSやAndroid向けのアプリを開発できるフレームワークです。

https://reactnative.dev/

Expoは、React Native製のアプリのビルドなどを行うためのツールです。手軽にモバイルアプリ開発に取り組みたい方にとって便利なツールです。

https://expo.dev/

Expoを使えばXcodeやAndroid Studioは使わずに開発・リリースすることも可能です。Expoが提供するアプリ「Expo Go」を使えば、iPhoneやAndroid端末で実機確認できます。

https://expo.dev/go

セットアップ

dependencies

最終的な依存関係は以下です。

package.json
package.json
{
  "name": "my-app",
  "version": "1.0.0",
  "main": "expo/AppEntry.js",
  "scripts": {
    "start": "expo start",
    "android": "expo start --android",
    "ios": "expo start --ios",
    "web": "expo start --web"
  },
  "dependencies": {
    "expo": "^51.0.0",
    "expo-status-bar": "~1.12.1",
    "nativewind": "^2.0.11",
    "react": "18.2.0",
    "react-native": "0.74.5",
    "tailwindcss": "3.3.2"
  },
  "devDependencies": {
    "@babel/core": "^7.24.0",
    "@types/react": "~18.2.79",
    "@types/react-native": "^0.73.0",
    "expo-cli": "^6.3.10",
    "typescript": "~5.3.3"
  },
  "private": true
}

node -v
v18.15.0

Expo CLIのインストールとセットアップ

React Nativeで開発したアプリを実機で確認するためには、Expoが提供する「Expo Go」アプリを使います。その前に以下の手順で、Expo Goのインストールとセットアップを行います。

ザックリ以下の手順です。

  • Expo CLIのインストール
  • Expoアカウントにログイン
  • 新規プロジェクトの作成
詳細は以下にまとめています。

Expo CLIのインストール

npm install -g expo-cli

Expoアカウントの作成(未登録の場合)してもらって、Expoアカウントへのログインします。

npx expo login

ここで、登録したメールアドレスとパスワードを入力してログインします。成功すると、アカウント名が表示されます。

Expoの新規プロジェクトを作成する

npx create-expo-app@latest --template

Expoテンプレートを使用して、新規プロジェクトを作成します。

実行後、プロジェクト名やテンプレートの選択肢(空のプロジェクトやTypeScriptなど)が表示されるので、お好みに選択していけば開発環境が整います。

今回は以下のように選択し、ダウンロードが完了しました。

✔ Choose a template: > Blank (TypeScript) - blank app with TypeScript enabled
✔ What is your app named? › my-app
✔ Downloaded and extracted project files.

✅ Your project is ready!

To run your project, navigate to the directory and run one of the following npm commands.

- cd my-app
- npm run android
- npm run ios
- npm run web

新規プロジェクトが作成されました。

tree  -L 1
.
├── App.tsx
├── app.json
├── assets
├── babel.config.js
├── node_modules
├── package-lock.json
├── package.json
└── tsconfig.json

3 directories, 6 files

「Expo Go」のインストールと実行

Expo Go(アプリ)を使うことで、React Nativeアプリを実行できます。このアプリをお持ちのスマホにインストールすれば、QRコードをスキャンするだけで作成したアプリの実機検証ができます。

インストールしていなければ、しましょう。

https://expo.dev/go

次に、開発サーバーを起動します。

npx expo start

実行すると、下記のような画面が表示されます。このQRコードをExpo Goアプリでスキャンし、開発中のアプリを実機確認できます。

このような画面が出てればOKです。

NativeWindのセットアップ

React NativeでTailwind CSSのようなスタイリングを活用できるNativeWindを導入し、実際に動作するアプリを作成してみましょう。今回はシンプルな設定から始めて、実機での動作を確認するまでの手順を説明します。

必要なファイル

React Native + NativeWindをセットアップするためのファイル構成です。

MyApp/
├── App.tsx               # アプリのエントリーポイント。
├── babel.config.js       # Babelの設定ファイル。NativeWindのBabelプラグインを設定します。
├── my-app.d.ts           # TypeScriptの型定義ファイル。NativeWindに関する型情報を追加します。(新規追加)
├── tailwind.config.js    # Tailwind CSSの設定ファイル。スタイルの適用範囲などを定義します。
└── tsconfig.json         # TypeScriptの設定ファイル。

今回はすべてのファイルをルートディレクトリに配置しますが、プロジェクトによりますが適切なディレクトリに格納することをお勧めします。

[参考] ディレクトリ配置の案
  • App.tsx
    • 一般的にはsrcディレクトリに置くと思います
      • src/App.tsx
  • babel.config.js
    • 一般的にはルートディレクトリに置くと思います
  • my-app.d.ts
    • 一般的にはsrcやtypesディレクトリに置くと思います
      • src/types/my-app.d.ts または types/my-app.d.ts
  • tailwind.config.js
    • 一般的にはルートディレクトリに置くと思います
  • tsconfig.json
    • 一般的にはルートディレクトリに置くと思います

Tailwind CSS と NativeWindのインストール

Tailwind CSS、NativeWind、そしてTypeScriptの型定義をインストールします。

npm i tailwindcss
npm i nativewind
npm i --save-dev @types/react-native

Tailwind CSSの設定ファイルを作成し編集する

Tailwind CSSの設定ファイルを生成します。

npx tailwindcss init

プロジェクトのルートにtailwind.config.jsファイルが追加されます。

次にtailwind.config.jsを開き、contentプロパティにTailwind CSSを適用する対象を記載します。

tailwind.config.js
/** @type {import('tailwindcss').Config} */
module.exports = {
+ content: ["./App.{js,jsx,ts,tsx}", "./components/**/*.{tsx,jsx,ts,js}"],
  theme: {
    extend: {},
  },
  plugins: [],
};

BabelにNativeWindプラグインを追加

下記の設定により、NativeWindがReact Nativeでのスタイリングを解釈できるようになります。

babel.config.js
module.exports = function (api) {
  api.cache(true);
  return {
    presets: ["babel-preset-expo"],
+   sourceMaps: true,
+   plugins: ["nativewind/babel"],
  };
};

設定内容の補足説明
  • sourceMapsの設定
    • sourceMaps: trueでデバッグ時にソースコードを追跡できるようにします
  • pluginsの設定
    • ["nativewind/babel"]でNativeWindを使用し、Tailwind CSS風のクラス名をReact Nativeに適用します

NativeWindは、Tailwind CSSのスタイリング手法をReact Nativeでも使えるようにするツールです。Babelプラグインを追加することで、Tailwind CSSのクラス名がReact Nativeのスタイルとして解釈され、UIに反映されます。これにより、開発者はスタイル管理を行うことができます。

TypeScriptの定義ファイルを追加

次に、TypeScriptでNativeWindを利用するための型定義ファイルをプロジェクトに追加し、以下の内容を記述します。

nativewind-env.d.ts
/// <reference types="nativewind/types" />

App.tsxにスタイリングを適用

最後に、App.tsxにモーダルを開閉させる簡単なコンポーネントを実装しました。コードはあくまでデモとしての参考にしていただければと思います。

App.tsx
import React, {useState} from "react";
import {Text, TouchableOpacity, View, Modal} from "react-native";

export default function App() {
  const [isModalVisible, setIsModalVisible] = useState(false);

  return (
    <View className="flex-1 items-center justify-center bg-gray-200">
      <Text className="text-2xl font-bold mb-4">モーダルが開くだけです</Text>

      {/* モーダルを開くボタン */}
      <TouchableOpacity
        onPress={() => setIsModalVisible(true)}
        className="mt-8 bg-customBlue px-6 py-2 rounded-lg"
      >
        <Text className="text-white text-lg">開く</Text>
      </TouchableOpacity>

      {/* モーダルの表示 */}
      <Modal transparent={true} visible={isModalVisible} animationType="fade">
        <View className="flex-1 justify-center items-center bg-black bg-opacity-100">
          <View className="bg-white p-8 rounded-lg shadow-lg w-4/5 max-w-sm">
            <Text className="text-xl font-bold mb-4">開きました</Text>
            <View className="items-center">
              <TouchableOpacity
                onPress={() => setIsModalVisible(false)}
                className="bg-customBlue px-6 py-2 rounded-lg"
              >
                <Text className="text-white font-semibold">閉じる</Text>
              </TouchableOpacity>
            </View>
          </View>
        </View>
      </Modal>
    </View>
  );
}

📱 実機での確認

📢 アナウンス「NativeWindのv4まもなく登場」

今回は、NativeWind v2(最新バージョン)の動作で検証しました。

v2では、classNameをビルド時にstyleへ変換しています。なので、動的なスタイルの変更は難しい構造になっています。

まもなく登場するv4ではclassNameの処理がビルド時だけでなく、実行時にも柔軟に行われるようになるそうです。これにより、たとえばアニメーションや条件によってスタイルを切り替えるような対応が可能になるかと思います。

v3はベータ版が存在しましたが正式リリースには至らず、v4へと移行されるみたいです。

詳しくは 👇

https://www.nativewind.dev/v4/overview

さいごに

読んでいただきありがとうございました。

Tailwind CSS を使ったことある人はぜひReact Nativeでも使ってみてください。

chot Inc. tech blog

Discussion