✅ Tailwind CSS+Reactの複数チェックボックス

2020-11-08 #Development

昨日 に続いて Tailwind CSS のカスタムフォームも触ってみました。カスタムフォームのCSSは別途プラグインを入れる必要があるんですね。 あとついでにReactで複数チェックボックスを扱う方法も調べてみてたんですが色々出てきて都度迷ってしまいそうなのでメモ。

インストール

$ yarn add @tailwindcss/custom-forms -D

プラグインを追加

// tailwind.config.js
module.exports = {
  // ...
  plugins: [require("@tailwindcss/custom-forms")],
};

コンポーネント側

import React, { useEffect, useState } from "react";

const CheckBox = (props) => {
  return (
    <>
      <input type="checkbox" className="form-checkbox" type="checkbox" id={props.name} name={props.name} checked={props.checked} onChange={props.onChange} value={props.value} />
      <label className="ml-2 text-sm" htmlFor={props.name}>
        {props.label}
      </label>
    </>
  );
};

const CheckBoxes = (props) => {
  const [checkedItems, setCheckedItems] = useState(props.checkedItems || []);

  const checkboxes = props.checkboxes || [
    {
      name: "checkbox_0",
      label: "item0",
      value: "0",
    },
  ];

  useEffect(() => {
    if (props.onUpdate) props.onUpdate({ checkedItems: checkedItems });
  }, [checkedItems]);

  const onChange = (e) => {
    if (e.target.checked) {
      setCheckedItems([...checkedItems, e.target.value]);
    } else {
      setCheckedItems(checkedItems.filter((i) => i !== e.target.value));
    }
  };

  const onReset = (e) => {
    setCheckedItems([]);
  };

  return (
    <>
      <fieldset className="my-2">
        <legend className="text-sm text-gray-700 mb-2">{props.legend || "Checkboxes"}</legend>
        {checkboxes.map((item) => {
          return (
            <div key={item.name} className="block items-center py-1">
              <CheckBox {...item} checked={checkedItems.includes(item.value)} onChange={onChange} />
            </div>
          );
        })}
        <div className="text-right">
          <button type="button" className="text-sm text-gray-500" onClick={onReset}>
            Reset
          </button>
        </div>
      </fieldset>
    </>
  );
};

export default CheckBoxes;

使う側

使い回ししたいので、onUpdate含めコンポーネントの中身は触らないで良いようにしておきました。

<CheckBoxes
  {...{
    onUpdate: onUpdateCheckboxes,
    legend: "Checkboxes",
    checkedItems: ["0", "1", "2"],
    checkboxes: [
      {
        name: "checkbox_0",
        label: "Item0",
        value: "0",
      },
      {
        name: "checkbox_1",
        label: "Item1",
        value: "1",
      },
      {
        name: "checkbox_2",
        label: "Item2",
        value: "2",
      },
    ],
  }}
/>

所感

ReactではVueのv-model的なものが無いので自前でなんとかしなければならなくてどう実装したらよいのか迷ったのですが、ちょっと調べてみたところ色々なやり方が出てきて悩ましいですね…

連想配列のcheckedItemsにスプレッド構文を使ってChangeイベントがあったものを { name: checked }みたいな感じで追加していく方法が比較的多くヒットしたのですが、これだと格納されているものには非アクティブなものが含まれているし全てのチェックボックスを触るまで抜けがある状態になってしまってなんだか違和感があるのでcheckedItemsを配列にして追加or削除をするようにしてみました。 APIに値を送信するような用途で使う時はアクティブなvalueだけが入った配列があると嬉しいので。

comments powered by Disqus
Profile
😛

石原 悠 / Yu Ishihara

デザインとプログラミングとヨーグルト作りが好きです。