TailwindCSSに入門してお申し込みフォームを作ってみる
バージョン
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 内を以下のように変更してましょう。
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;
慣れてしまえばサクサク書けるようになりますが、
不慣れなうちはチートシートを積極的に活用するのが良いかと思います。
フォームを作成する
src 配下の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 の個人的な一番のメリットとしては、やはり命名を考えずに書けることだと思います。命名のストレスから解放されるので開発スピードも上がります。
興味がある方は是非、試してみてはいかがでしょうか。
参考
Discussion