React AriaでつくるUIコンポーネント 第3回 Tailwind CSSと組み合わせる

React Aria Componentは構造がしっかりしているため、他のアニメーションライブラリと組み合わせることもできます。今回はTailwind CSSでスタイリングやアニメーションの調節を行います。

発行

著者 小山田 晃浩 フロントエンド・エンジニア
React AriaでつくるUIコンポーネント シリーズの記事一覧

前回まで

React Aria ComponentsのModalDialogを利用しながら、モーダルUIを実装しました。

自力で実装すると面倒な、モーダルとして動き、キーボードトラップ、アクセシビリティ対応をすべて済ませた状態のコンポーネントを元に開発を進められるメリットをおわかりいただけたと思います。

今回は引き続き、モーダルUIを使いつつ、実務で使われることの多いTailwind CSSを導入し、スタイルやアニメーションの実装方法を解説します。

Tailwind CSSそのものの説明は割愛しますが、次のシリーズなどが参考になります。

Tailwind CSSでスタイルをつける

Tailwind CSSで指定する例を紹介します。

Tailwind CSSの初期設定

Tailwind CSSの利用に当たり、前回までのコードからmodal.cssを取り除き、Tailwind CSSを加えていきましょう。

Tailwind CSSのインストール

npm i -D tailwindcss postcss

tailwind.config.jspostcss.config.jsも新規に追加します。

tailwind.config.js

/** @type {import('tailwindcss').Config} */
export default {
  content: ["./src/**/*.{js,jsx,ts,tsx}"],
  theme: {
    extend: {},
  },
  plugins: [],
}

postcss.config.js

export default {
  plugins: {
    tailwindcss: {},
  },
}

Tailwind CSSを読み込めるCSSファイルを用意します。

src/tailwind.css

@tailwind base;
@tailwind components;
@tailwind utilities;

Viteのエントリーポイントに利用してるindex.htmlには、上記のCSSファイルを読み込みます。

index.html

<link rel="stylesheet" href="./src/tailwind.css">

Tailwind CSSに関する設定は以上です。

スタイルの実装

App.tsxから、import './modal.css'を削除して前回までのスタイルを外します。

独自Modalに対して、Tailwind CSSで見た目をつけていきましょう。

Modalコンポーネントを利用すると、実は暗黙のうちにModalOverlayコンポーネントも展開されています。Tailwind CSSでの見た目制御の際にはオーバーレイ部分にもTailwind CSSのCSSを適用したいため、明示的にModalOverlayを付け加えています。

以下はModalOverlayを追加して、Tailwind CSSでスタイリングを終えた状態です。

ModalOverlayとTailwind CSSのスタイルを追加(App.tsx)

import { useState } from "react";
import { Modal, ModalOverlay, Dialog } from "react-aria-components";

function App() {
  const [isOpen, setOpen] = useState(false);
  return (
    <>
      <button className="border" onClick={() => setOpen(true)}>
        開く
      </button>
      <ModalOverlay
        className="fixed inset-0 z-50 flex items-center justify-center bg-black bg-opacity-50"
        isOpen={isOpen}
        isDismissable
        onOpenChange={setOpen}
      >
        <Modal className="max-w-80 rounded-md border bg-white">
          <Dialog className="overflow-auto p-8" aria-label="操作ダイアログ">
            <p>モーダルの内容</p>
            <button className="border" onClick={() => setOpen(false)}>
              閉じる
            </button>
          </Dialog>
        </Modal>
      </ModalOverlay>
      <input placeholder="フォーカス検証用" className="border" />
    </>
  );
}

export default App;

Tailwind CSSでのアニメーション

Tailwind CSSでのアニメーションの実装において、React Ariaのドキュメントでは、tailwindcss-animateを利用する例も紹介されています。

これに倣って、tailwindcss-animateでアニメーションを付与してみましょう。tailwindcss-animateをインストールしておきます。

tailwindcss-animateのインストール

npm install -D tailwindcss-animate

tailwind.config.jsplugins:に、tailwindcss-animateを追加します。

tailwind.config.js

/** @type {import('tailwindcss').Config} */
export default {
  content: ["./src/**/*.{js,jsx,ts,tsx}"],
  theme: {
    extend: {},
  },
  plugins: [require("tailwindcss-animate")],  // この行を追加
};

そして、React Ariaのアニメーション用のdata属性をTailwind CSSで利用するため、data-[entering]data-[exiting]のクラス名接頭辞をつけたtailwindcss-animateのクラス名を追加していきます。

前回解説したとおり、React Aria Componentのモーダルは、CSS Animationによるアニメーション終了を待ってからアンマウントしてくれます。アニメーションを待つ処理を自身で用意する必要はなく、クラス名を書くだけでいいのです。

tailwindcss-animateではanimate-in/animate-outで、enter時やexit時のアニメーションが設定でき、さらにどんな種類のアニメーションにするかを、fade-inspin-inzoom-inなどで指定します。

詳しくは、tailwindcss-animateの公式ドキュメントでも確認できます。

アニメーションのクラス名付与(App.tsx)

import { useState } from "react";
import { Modal, ModalOverlay, Dialog } from "react-aria-components";

function App() {
  const [isOpen, setOpen] = useState(false);

  return (
    <>
      <button className="border" onClick={() => setOpen(true)}>
        開く
      </button>
      <ModalOverlay
        className="data-[entering]:animate-in data-[entering]:fade-in data-[exiting]:animate-out data-[exiting]:fade-out fixed inset-0 z-50 flex items-center justify-center bg-black bg-opacity-50"
        isOpen={isOpen}
        isDismissable
        onOpenChange={setOpen}
      >
        <Modal className="data-[entering]:animate-in data-[entering]:zoom-in data-[exiting]:animate-out data-[exiting]:zoom-out max-w-80 rounded-md border bg-white">
          <Dialog className="overflow-auto p-8">
            <p>モーダルの内容</p>
            <button className="border" onClick={() => setOpen(false)}>
              閉じる
            </button>
          </Dialog>
        </Modal>
      </ModalOverlay>

      <input placeholder="フォーカス検証用" className="border" />
    </>
  );
}

export default App;

まとめ

React Aria Componentから既存のCSSを剥がし、実務でも多く使われるTailwind CSSでスタイリングとアニメーションの付与を行ってみました。案件の要件との折り合えさえよければ、かなり柔軟に使っていくことができるでしょう。

次回は、Tailwind CSSでは少しクラス名などが煩雑になりがちなアニメーション部分を別のアニメーションライブラリに担当させてみます。