簡易的なプルダウンを作ってみよう!
みなさんこんにちは!
PlayGround AdventCalendar2024 9日目はフロントエンドコース所属のrikuが担当します。プログラミングを学び始めてから2年目に突入していますが、Reactがまだきちんと使いこなせなかったり、型エラーが起こったりなど、難しい部分が多いなと感じています…。
今回はReact,TypeScript,Tailwind CSSを少しづつ使って、簡易的なプルダウンを作ってみました。力不足な部分が多いので、温かい目で読んでくれると幸いです!
1.はじめに
プルダウンの作成は、HTMLだと<section>
を用いたり、
最近流行りのshadcn/uiだとSelect
を用いてみたり、
と比較的簡単に実装することができます。しかし、上記の内容は自分でカスタマイズしにくいという難点…。
上記の内容を使わずに実際に作ってみようとすると、
- なんかトグルの開閉が上手くいかない
- 選択肢の部分はどこにいった?
- 自分が欲しい位置になかなか合わない…
など、すごく頭を悩ませる事態になりました。
今回は、そのつまづきやすいポイントを押さえながら、段階ごとに分けてトグルボタンの作成について紹介していきます!
2.完成図と環境構築
完成図
以下に完成品とコードを置きました! (こちらはstorybook未導入です)
ディレクトリ構成
環境構築
- viteを使って、Reactのプロジェクトを作成します(ReactとTypeScript を選択してください)
npm create vite@latest
- Storybookの導入
自分はStorybook上でも確認したかったので導入しました。無くても作成できるので飛ばしても大丈夫です。
npx storybook@latest init
- Tailwind CSSの導入
(要注意!)ただインストールするだけでは使うことができません!
次にファイルを操作していきます
tailwind.config.js
の「content」の部分に、Tailwind CSSを反映させたいファイルを書く。
- プロジェクトを作成したときに出てきた、
index.css
に以下の内容を追加する。
(tailwind.css
など新たにファイルを作成し、その中に以下の内容を記述しても構いません。)
postcss.config.cjs
というファイルを作成し、以下の内容を追加する。(自分もここで詰まりました)
- Storybookを導入した人は
preview.ts
に以下のimport文を追加する。
(tailwind.css
など新たにファイルを作成している場合は、import文の参照パスもそのファイルが指定できるように変えてください。)
これで環境構築が完了です!
3.useStateで選択肢の開閉をしてみる
ボタンを押すと、選択肢の部分が開いたり閉じたりする実装を行います
開閉だけだと「イベントハンドラ(onClick
)」と状態管理の「useState
」を用いる事で上手くいきそうです
(注意!)単にoption
と指定すると、何を指しているのかが分からないのでエラーが起こります。listという配列のvalue
を表示させたいのでoption.value
としてあげましょう
4.Tailwind CSSで調整してみよう
物足りなさが半端ないので、Tailwind CSSで調整していきましょう。
枠組みや幅の調整がメインです
公式によると「A utility-first CSS framework」、実用性の高いCSSフレームワークということである。実際に使うと分かるが、通常のCSSよりコード量が短くなるというメリットがある。 ただ、通常のCSSと書き方が大幅に変わってくるので、使い始めはなかなか慣れないというデメリットもある。(慣れれば楽しいです!)
Tailwind CSS - Rapidly build modern websites without ever leaving your HTML.
また、書き方をまとめてくれているサイトが存在しているので、そちらも参考にしてほしいです!
Tailwind CSS CheatSheet for Beginners and Not Only
【補足】
overflow-y-scroll h-auto max-h-[200px]
選択肢の表示する高さを制限し、幅を超えたらスクロールするという実装です。
y方向をスクロール、表示高さは200pxまでという内容ですね。
途中経過はこんな感じになるかと思います!
5.大きさを引っ張ってくる、位置を動かす
今のままだと、選択肢が枠組みより大きくなっている状況です。今回はuseRefを用いて、親のコンポーネント(App.tsx
)から幅を取得し、子のコンポーネント(toggle.tsx
)に値を渡してあげましょう。
幅はoffsetWidth
で取得することができ、その値をtitleWidth
というstateにて管理しています。useEffect
を用いる事で1回だけ実行するようにしています。(これがないと実行されません)
(要注意!)どこを参照するか分からないので、<div>
にref={titleRef}をつけ忘れないようにしましょう!
TypeScriptは型定義が基本!なので、propsにも型をつけてあげましょう。
(分割代入であるので、titleWidth
を{ }に挟めることを忘れないでください!)
最後に位置調整です。固定するものにrelative
、動かすものにabsolute
をつけることによって、選択肢を自由に動かすことができます!
buttonと選択肢の場所を変え、さらにtop-full
をbottom-full
に変えました。
これで配置の心配も無くなりますね!
これでプルダウンボタンが完成です!
6.チェックマークをつけてみよう
ボタンは完成しましたが、何が選択されているかいまいちよく分かりませんよね。現在選択されているものにチェックマークをつけてみましょう!基本はuseState
です!
export const ExampleToggle: React.FC<toggleProps> = ({ titleWidth }) => {
// 省略
const [selectedOption, setSelectedOption] = useState<string>("");//追加
// closeToggleの中身を変える
const closeToggle = (value: string) => {
const newValue = selectedOption === value ? "" : value;
setSelectedOption(newValue);
setIsToggle(false);
};
return(
/*省略*/
{isToggle && (
<div
className="absolute z-1 top-full left-0"
style={{ width: `${titleWidth}px` }}
>
<div className="flex flex-col overflow-y-scroll m-[4px] h-auto max-h-[200px]">
{lists.map((option) => (
<button
className="flex flex-row justify-between items-center cursor-pointer"
key={option.value}
onClick={() => closeToggle(option.value)}
>
<p>{option.value}</p>
{selectedOption === option.value && <p>✅</p>}
</button>
))}
</div>
</div>
)}
/*以下省略*/
}
7.おわりに
ここまで読んでくださってありがとうございました! 簡易的ではありますが、少しだけReact,TypeScript,Tailwind CSSの知識が身についたかと思います。このプルダウンはフィルター機能にも多く使われていたりするので覚えておいて損は無いと感じます!
理解しずらいところだと思うので、少しでも手を動かして慣れていってもらえばと思います!
明日はhanakaさんです!よろしくお願いします!