Select box with placeholder in React

kimizuy

はじめに

こんにちは。kimizuy です。

今回は React を使ってプレースホルダー付きのシンプルなセレクトボックスの実装例を紹介します。

セレクトボックスでテキストフィールドのようなプレースホルダーを表現するには一工夫が必要だったので、本記事ではそこで得た知見を共有できたら幸いです。

1 つのファイルで管理したいという目的のみでスタイリングには styled-components を使っています。適宜、ご自身の環境に読みかえてください。

tldr

早速、コード例をご紹介します。

こだわりポイントは非クリック時のセレクトボックスの文字色です。

プレースホルダーのときはライトグレー、それ以外を選択しているときはブラックにして、有効/無効な値を選択しているかがわかるような見た目にしました。

CodeSandbox も用意しました。実際に触って挙動を確かめてみてください。

iimport styled from "styled-components";
import "./styles.css";

const StyledSelect = styled.select`
  width: 200px;
  height: 50px;
  background-color: white;
  &.-placeholder {
    color: lightgrey;
  }
`;

const StyledOption = styled.option`
  color: black;
  background-color: white;
`;

const Placeholder = styled.option`
  color: lightgrey;
  background-color: white;
`;

type Props = {
  options: { value: string; label: string }[];
} & React.SelectHTMLAttributes<HTMLSelectElement>;

const SelectBoxWithPlaceholder = ({
  options,
  placeholder,
  onChange,
  ...props
}: Props) => {
  return (
    <StyledSelect
      {...props}
      className={placeholder ? "-placeholder" : ""}
      onChange={(event) => {
        onChange?.(event);
        if (placeholder) {
          if (event.currentTarget.value) {
            event.currentTarget.classList.remove("-placeholder");
            return;
          }
          event.currentTarget.classList.add("-placeholder");
        }
      }}
    >
      {placeholder && (
        <Placeholder value="" selected>
          {placeholder}
        </Placeholder>
      )}
      {options.map(({ value, label }, i) => {
        return (
          <StyledOption key={value} value={value}>
            {label}
          </StyledOption>
        );
      })}
    </StyledSelect>
  );
};

const sample: Props["options"] = [
  { value: "foo", label: "foo" },
  { value: "bar", label: "bar" },
  { value: "baz", label: "baz" }
];

export default function App() {
  return (
    <div className="App">
      <SelectBoxWithPlaceholder
        options={sample}
        placeholder="選択してください"
      />
    </div>
  );
}

簡単な解説

onchange のイベントハンドラ内で -placeholder クラス(BEM でいうモディファイアクラスみたいなの)を値の有無に応じて追加したり削除したりしています。

例えば、値がある場合はプレースホルダー以外の選択肢が選ばれている状態なので、-placeholder を削除する、といった処理をしています。

これによってセレクトボックスの文字色を変更しています。

      onChange={(event) => {
        onChange?.(event);
        if (placeholder) {
          if (event.currentTarget.value) {
            event.currentTarget.classList.remove("-placeholder");
            return;
          }
          event.currentTarget.classList.add("-placeholder");
        }
      }}

おわりに

今回はプレースホルダーのあるセレクトボックスの実装例をご紹介しました。

<option> の見た目は OS やブラウザに大きく依存しているため、スタイルで融通が効きづらい点も覚えておくといいでしょう(参考)。

僕は最近まで知りませんでした。

以上、本記事が誰かのお役に立てれば幸いです。

Gaji-Laboでは、Jamstackが得意なフロントエンドエンジニアを募集しています

弊社ではJamstackの知見で事業作りに貢献したいフロントエンドエンジニアを募集しています。大きな制作会社や事業会社とはひと味もふた味も違うGaji-Laboを味わいに来ませんか?

もちろん、一緒にお仕事をしてくださるパートナーさんも随時募集中です。まずはお気軽に声をかけてください。お仕事お問い合わせや採用への応募、共に大歓迎です!

求人応募してみる!

kimizuy

投稿者 山崎 輝瑞

React, Redux, TypeScript プロジェクトでフロントエンド領域を担当。個人でも Next.js アプリの開発をしています。日課はRSSで取得した技術記事を読むこと、最近の関心は Core Web Vitals です。将来はでかい犬が飼いたいです。