スタイリングがもっと楽しくなる!CVAとTailwind CSSで実現するVariant管理

フロントエンド開発において、スタイリングはデザインの自由度と生産性を両立させるための重要な要素です。Tailwind CSSはその手軽さとパフォーマンスで人気がありますが、より柔軟なスタイリングを求める場面もあるでしょう。一方で、CSS-in-JSのような複雑なアプローチに踏み込むのは躊躇われた経験がある方は少なくないかなと思います。そんな時におすすめしたいのが「Class Variance Authority(CVA)」です。CVAは、Tailwind CSSを活用しつつ、variantsの管理やスタイリングを簡素化するためのライブラリです1。このブログでは、CVAを利用することで、いかに効率的に自由度の高いスタイリングが可能になるかをご紹介します。

CVAのある時・ない時

CVAがどんなものかを説明するには、実際のコードを見てみるのが一番です。まずは、CVAを使わずにTailwind CSSだけでスタイリングを行う場合を考えてみましょう。

PrimaryとSecondaryの2つのVariantを持つボタンを作成するとします。この場合、以下のようなコードになるでしょう。

import type { FC, PropsWithChildren } from "react";

type Props = {
    variant: "primary" | "secondary";
};
export const ButtonWithoutCva: FC<PropsWithChildren<Props>> = ({
   variant,
   children,
}) => (
    <button
        type="button"
        className={`px-2 py-1 rounded text-white ${variant === "primary" ? "bg-indigo-500" : variant === "secondary" ? "bg-gray-600" : ""}`}
    >
        {children}
    </button>
);

同じコンポーネントをCVAを使って書くと、以下のようになります。

import { type VariantProps, cva } from "class-variance-authority";
import type { FC, PropsWithChildren } from "react";

const buttonVariant = cva("px-2 py-1 rounded text-white ", {
  variants: {
    variant: {
      primary: "bg-indigo-500",
      secondary: "bg-gray-600",
    },
  },
  defaultVariants: {
    variant: "primary",
  },
});
type Props = VariantProps<typeof buttonVariant>;
export const ButtonWithCva: FC<PropsWithChildren<Props>> = ({
  variant,
  children,
}) => (
  <button type="button" className={buttonVariant({ variant })}>
    {children}
  </button>
);

cvaは、クラスのバリエーションを作成するための関数です。 これを使って、ボタンのベースクラスとバリエーションbuttonVariantを定義しています。 共通のクラスとしてpx-2 py-1 rounded text-whiteを指定し、 variantsオプションで、バリエーションを指定しています。ここでは variantという名前で、primarysecondaryの二種類のバージョンを設定しています。primarybg-indigo-500で、secondarybg-gray-600で、それぞれ背景色を指定しています。 defaultVariantsでは、デフォルトのバリエーションを指定しています。

そして、VariantPropsを使ってbuttonVariantからプロパティの型を作ります。

ButtonWithCvaコンポーネントを利用する際、以下のようにvariantプロパティを指定する際はdefaultprimaryが候補として表示されます。

Capture of Completion

以下のリンクから、「CVAのある時・ない時」で作ったコンポーネントをStackblitzで使ってみることができるので、興味のある方はお試しください。

https://stackblitz.com/~/github.com/toyamarinyon/hello-cva

まとめ

Tailwind CSS使ってスタイリングをしていて、クラスの管理が煩雑になってきたな、という時にはCVAを使ってみるとスッキリするかもしれません。

Tailwind CSSとCVAを使った、大規模な実装例を見てみたい時には https://ui.shadcn.com/ を参考にしてみてください。


  1. Tailwind CSS以外にもCSS Modulesなどとも組み合わせることが可能ですが、本ブログではTailwind CSSを前提として説明しています。