1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

ReactとTailwindCSSで5つ星評価のUIを実装する

Posted at

React,Tailwindを使って、星で評価を投稿するUIを実現する機会があり、
どう実現するか悩み検索するも、なかなか記事が見つからなかったので、私が実際に書いたコードを元に今回記事を書いてみました。

使っている技術は

技術 バージョン
React.js 17.0.38
Tailwind CSS 3.0.13
TypeScript 4.5.4

です。完成形のイメージは以下のようなものです。

star 14.56.55.gif

星アイコンの実装

まずは星のアイコンを実装します。
ここでは、selectedがTrueなら黄色、selectedがFalseならばグレーになるようにします。

スクリーンショット 2022-01-14 23.49.01.png スクリーンショット 2022-01-14 23.49.13.png

以下はReactIconというnpmを利用していますが、SVGアイコンで実装してもそれほど変わりません。

import React, { VFC } from "react";

import { AiFillStar } from "react-icons/ai";

type PropsType = {
  selected: boolean;
  size?: string;
};

export const ColorizeStarIcon: VFC<PropsType> = ({
  selected,
  size,
}: PropsType) => {
  const color = selected ? "text-yellow-400" : "text-gray-100";
  const hoverColor = selected ? "text-gray-100" : "text-yellow-400";

  return (
    <AiFillStar
      icon="fillStar"
      color={color}
      className={`hover:${hoverColor}`}
      size={size}
    />
  );
};

このアイコンのポイントは、

  1. テキストの色を 選択済みの場合は黄色、選択されていなければグレーにする
  2. Hoverされたときのテキストの色は、選択済みの場合はホバーされるとグレーになる、選択されていなければホバーされると黄色になる

という この部分です。

  const color = selected ? "text-yellow-400" : "text-gray-100";
  const hoverColor = selected ? "text-gray-100" : "text-yellow-400";

星を並べる

続いて上で作った星を並べていきます。

スクリーンショット 2022-01-14 23.52.51.png

  • 星の数(count)
  • 選択された星の数(value)
  • 星を変更できるか(readonly)
  • 星の変更時の関数(onChange)

をpropsで渡されるコンポーネントを作成します。

以下、コードをしまします。詳しくは下で解説します。

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

import { ColorizeStarIcon } from "~/components/atoms";

type PropsType = {
  count: number;
  value: number;
  readonly?: boolean;
  size?: string;
  onChange?: (value: number) => void;
};

export const StarRatingField: VFC<PropsType> = ({
  count,
  value,
  readonly = false,
  size,
  onChange,
}: PropsType) => {
  const [hover, setHover] = useState(-1); //  Hover時にも色を変更できるように、hoverされている星の数を管理します

  const onClick = (starNumber: number) => {
    if (readonly) return;

    onChange && onChange(starNumber);
    setHover(-1);
  };

  const onHover = (starNumber: number) => {
    if (readonly) return;

    setHover(starNumber);
  };

  const onMouseLeave = () => {
    if (readonly) return;

    setHover(-1);
  };

  const currentValue = hover >= 0 ? hover : value;

  return (
    <>
      <ul className="flex items-center space-x-1">
        {[...Array(count)] // countの数だけの要素を持った配列を作成
          .map((_, i) => i + 1)
          .map((starNumber) => (
            <li
              title={`${starNumber} star`}
              key={starNumber}
              onClick={() => onClick(starNumber)}
              onMouseOver={() => onHover(starNumber)}
              onMouseLeave={() => onMouseLeave()}
              className={readonly ? "" : "cursor-pointer"}
            >
              <ColorizeStarIcon
                selected={starNumber <= currentValue} // currentValue以下のindexは、selectedをTrueにする
                size={size}
              />
            </li>
          ))}
      </ul>
    </>
  );
};

ポイントは、

  1. 星(count)の数だけ配列を作る: [...Array(count)]
  2. 選択された星の数(value)の数だけ、先ほど作った ColorizeStarIconコンポーネントのselectedをTrueにします
  3. Hover時にも色を変更できるように、hoverされている星の数を管理します
  4. マウスがhoverされたときには、そのhoverされた星のindex+1番にhoverの数を更新します
  5. マウスのhoverが外れたとき と クリックされたとき には、そのhoverの数を-1に更新します

ざっくりですが、上記のようにすると、以下のような星の評価をできるUIを実装できます。

star 14.56.55.gif

必要になったときにご参考ください。

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?