🎨

TailwindCSSに入門してお申し込みフォームを作ってみる

2022/12/13に公開

バージョン

React 18.2.0
TailwindCSS v3.2

はじめに

今回は React + TypeScript + TailwindCSS
簡単なお申し込みフォームを作っていきます。

あくまで見た目だけの実装(TailwindCSS を使いたいだけ)なので、
送信処理など裏側の処理は実装しませんのでご了承ください。

以下、完成図です。

サンプル

TailwindCSS とは?

TailwindCSS はオープンソースの CSS フレームワークです。
Bootstrap などのフレームワークとは異なり、あらかじめコンポーネントが用意されておらず、utility class を用いて独自デザインのコンポーネントを構築できます。

React + TypeScript + TailwindCSS の準備

まずは React + TypeScript 導入するために、
以下のコマンドを実行します。

$ npx create-react-app my-app --template typescript

インストールが完了したら、続けて TailwindCSS を導入します。

TailwindCSS の導入は、yarnもしくはnpm経由でインストールする方法
CDNでTailwindCSSファイルを読み込む方法が存在します。

今回は簡単なCDNでTailwindCSSファイルを読み込む方法で実装したいと思いますが、CDN 経由だと Tailwind のデフォルトテーマをカスタマイズできなかったり、他のプラグインが導入できなかったりするので、細かく触りたいならyarnもしくはnpm経由でインストールする方法が良いかと思います。

src 配下のindex.tsxを編集します。
root.render 内を以下のように変更してましょう。

index.tsx
root.render(
  <React.StrictMode>
    <head>
      <link
        href="https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css"
        rel="stylesheet"
      />
    </head>
    <App />
  </React.StrictMode>
);

これだけで導入できました。
とても簡単ですね。

続けて、TailwindCSS の utility class を活用してフォームの見た目を作っていくのですが、
その前に TailwindCSS の基礎を解説しておきます。

TailwindCSS の基礎

基本的な書き方を押さえていきます。

たとえばmt-1だと、CSS で記載する場合、
margin-top: 0.25rem;(4px)と同義となります。

m はmargin、p はpaddingといった感じで省略されていて、
t がtop、b がbottom、l がleft、r がrightです。

mt-1の後ろにつく数字ですが、
この数値が 2、3、4 と大きくなるほど、適用するサイズも大きくなります。

次は文字の場合です。

<p className="text-2xl text-black-500 font-bold text-center mb-5">
  お申し込みフォーム
</p>

text-2xl は文字サイズの指定、font-size: 1.5rem;line-height: 2rem;※24px
text-black はテキストの色指定、color: rgb(0 0 0);
font-bold で太さの指定、font-weight: 700;
text-center で中央寄せ、text-align: center;
といった感じとなります。

また、レスポンシブにする場合はmd:w-2/3のように指定します。
これは画面幅が 768px 以上の場合に、この tailwind の CSS が適用されます。

レスポンシブ幅は以下のようになります。

sm: min-width:640px;
md: min-width:768px;
lg: min-width:1024px;
xl: min-width:1280px;

慣れてしまえばサクサク書けるようになりますが、
不慣れなうちはチートシートを積極的に活用するのが良いかと思います。

https://nerdcave.com/tailwind-cheat-sheet

フォームを作成する

src 配下のApp.tsxを編集して、
以下のように書き換えます。

ひとまずソースコードをコピペしてもらって、
実際に細かいところを触ってもらうのが分かりやすいかと思います。

App.tsx
import { useState } from "react";

export const App = () => {
  const [isSubmitted, setIsSubmitted] = useState(false);
  const [lastName, setLastName] = useState("");
  const [firstName, setFirstName] = useState("");
  const [email, setEmail] = useState("");
  const [tel, setTel] = useState("");

  const onChangeLastName = (e: any) => {
    setLastName(e.target.value);
  };

  const onChangeFirstName = (e: any) => {
    setFirstName(e.target.value);
  };

  const onChangeEmail = (e: any) => {
    setEmail(e.target.value);
  };

  const onChangeTel = (e: any) => {
    setTel(e.target.value);
  };

  const onSubmit = (e: any) => {
    e.preventDefault();
    if (lastName !== "" && firstName !== "" && email !== "" && tel !== "") {
      setIsSubmitted(true);
    }
  };

  return (
    <div className="mt-40 mx-20">
      <div className="flex justify-center mt-32 mx-10 mb-10">
        <form className="w-full max-w-2xl" onSubmit={onSubmit}>
          <p className="text-2xl text-black font-bold text-center mb-5">
            お申し込みフォーム
          </p>
          <div className="md:flex md:items-center mb-6">
            <div className="md:w-1/3">
              <label
                className="block text-black font-bold md:text-right mb-1 md:mb-0 pr-4"
                htmlFor="inline-last-name"
              ><text className="text-white bg-red-500 font-normal text-sm ml-2 p-0.5 rounded-md">
                  必須
                </text>
              </label>
            </div>
            <div className="md:w-2/3">
              <input
                className="bg-gray-200 appearance-none border-2 border-gray-400 rounded w-full py-2 px-4 text-gray-700 leading-tight focus:outline-none focus:bg-white focus:border-purple-500"
                type="text"
                defaultValue=""
                placeholder=""
                onChange={onChangeLastName}
              />
            </div>
          </div>
          <div className="md:flex md:items-center mb-6">
            <div className="md:w-1/3">
              <label
                className="block text-black font-bold md:text-right mb-1 md:mb-0 pr-4"
                htmlFor="inline-first-name"
              ><text className="text-white bg-red-500 font-normal text-sm ml-2 p-0.5 rounded-md">
                  必須
                </text>
              </label>
            </div>

            <div className="md:w-2/3">
              <input
                className="bg-gray-200 appearance-none border-2 border-gray-400 rounded w-full py-2 px-4 text-gray-700 leading-tight focus:outline-none focus:bg-white focus:border-purple-500"
                type="text"
                defaultValue=""
                placeholder=""
                onChange={onChangeFirstName}
              />
            </div>
          </div>

          <div className="md:flex md:items-center mb-6">
            <div className="md:w-1/3">
              <label className="block text-black font-bold md:text-right mb-1 md:mb-0 pr-4">
                メールアドレス
                <text className="text-white bg-red-500 font-normal text-sm ml-2 p-0.5 rounded-md">
                  必須
                </text>
              </label>
            </div>
            <div className="md:w-2/3">
              <input
                className="bg-gray-200 appearance-none border-2 border-gray-400 rounded w-full py-2 px-4 text-gray-700 leading-tight focus:outline-none focus:bg-white focus:border-purple-500"
                type="email"
                value={email}
                defaultValue=""
                placeholder="例) example@gmail.me"
                onChange={onChangeEmail}
              />
            </div>
          </div>

          <div className="md:flex md:items-center mb-6">
            <div className="md:w-1/3">
              <label className="block text-black font-bold md:text-right mb-1 md:mb-0 pr-4">
                電話番号
                <text className="text-white bg-red-500 font-normal text-sm ml-2 p-0.5 rounded-md">
                  必須
                </text>
              </label>
            </div>
            <div className="md:w-2/3">
              <input
                className="bg-gray-200 appearance-none border-2 border-gray-400 rounded w-full py-2 px-4 text-gray-700 leading-tight focus:outline-none focus:bg-white focus:border-purple-500"
                type="text"
                defaultValue=""
                placeholder="例) 03-1234-5678"
                onChange={onChangeTel}
              />
            </div>
          </div>
          <div className="flex justify-center">
            {isSubmitted ? (
              <div>
                <p className="text-green-500 text-lg text-bold">
                  お問合せを送信いたしました。
                </p>
              </div>
            ) : (
              <button
                className={
                  "py-3 lg:py-3 px-14 lg:px-14 text-white-500 font-bold rounded-3xl bg-blue-400 hover:shadow-teal-md transition-all outline-none text-white"
                }
                type="submit"
              >
                送信
              </button>
            )}
          </div>
        </form>
      </div>
    </div>
  );
};

export default App;

ちなみに送信処理は実装しないと書きましたが、useState を使って、ボタンが押されたか判定して、
全項目が問題なければメッセージを出すようにしています。

まとめ

React + TypeScript + TailwindCSS で、めちゃ簡単にお申し込みフォームを実装できました。
TailwindCSS の個人的な一番のメリットとしては、やはり命名を考えずに書けることだと思います。命名のストレスから解放されるので開発スピードも上がります。

興味がある方は是非、試してみてはいかがでしょうか。

参考

https://tailwindcss.com/docs/guides/create-react-app

GitHubで編集を提案
catallaxy tech blog

Discussion