Shadcn/UIの中身を詳しくチェック
なんでパッケージではなくソースコード?
ユーザーがコンポーネントのビルドとスタイルを自由に決定できるようにするためです。
基本設定から始めて、好きなようにコンポーネントをカスタマイズすることができます。
npmパッケージの場合、スタイルが固定されているため変更が難しいですが、Shadcn/UI
はソースコードで提供されているため、より柔軟にカスタマイズが可能です。
Shadcn/UI
は、「コンポーネントのデザインと実装は分離されるべきだ」というコアな原則に基づいて作られています。そのため、すべてのコンポーネントは2つのレイヤー構造で構成されています。
構造と動作レイヤー
- Headlessな実装:
Shadcn/UI
のコンポーネントは「headless」な形で実装されています。「headless」とは、UIの機能部分だけを提供し、具体的なスタイリングは含まないことを意味します。 - Radix UIの活用:
Shadcn/UI
は、Accordion
やPopover
、Tabs
などの複雑な動作を実装するために、Radix UIという有名な「headless UIライブラリ」を使用しています。このライブラリを使うことで、スタイルなしでも多様な動作を簡単に適用できます。
https://www.radix-ui.com/
スタイルレイヤー
- Tailwind CSSの活用:
Shadcn/UI
のスタイリングにはTailwind CSSが中心に使われています。Tailwind CSSは柔軟で強力なスタイリングツールであり、コンポーネントに迅速にスタイルを適用することができます。 - Figmaとの連携: デザインツールとしてFigmaを使用している場合、このアプローチにより、Tailwind CSSとFigmaの変数を連動させてデザインシステムを管理できます。つまり、Figmaで定義したデザイン要素(色やフォントなど)をTailwind CSSで簡単に追跡し、反映させることができます。
https://www.figma.com/community/plugin/1222415071406554904/tokens-to-tailwind-css
コンポーネントの実装詳細
shadcn/ui Badge
BadgeコンポーネントはTailwind CSSを使ってスタイリングされたコンポーネントです。主なコンセプトは、スタイルを簡単に適用および変更できるようにすることです。
import * as React from "react";
import { cva, type VariantProps } from "class-variance-authority";
import { cn } from "@/lib/utils";
const badgeVariants = cva(
"inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
{
variants: {
variant: {
default: "border-transparent bg-primary text-primary-foreground hover:bg-primary/80",
secondary: "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
destructive: "border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80",
outline: "text-foreground",
},
},
defaultVariants: {
variant: "default",
},
}
);
export interface BadgeProps extends React.HTMLAttributes<HTMLDivElement>, VariantProps<typeof badgeVariants> {}
function Badge({ className, variant, ...props }: BadgeProps) {
return <div className={cn(badgeVariants({ variant }), className)} {...props} />;
}
export { Badge, badgeVariants };
cva関数
この関数は、さまざまなスタイルのバリエーションを定義するために使用されます。
例えば、「デフォルト(Default)」や「セカンダリー(Secondary)」といったスタイルを定義し、どのスタイルをデフォルトに設定するかを決めることができます。
Badgeコンポーネントに共通するスタイルと各バリエーションスタイルがここで指定されています。
BadgePropsインターフェース
Badgeコンポーネントが受け取るプロパティを定義しています。基本的にHTMLの<div>
要素の属性と、Badge独自のプロパティであるvariant
を使用できるようにします。
Badgeコンポーネント
Badgeコンポーネントは<div>
要素を使ってバッジを作成します。variant
というプロパティに応じてスタイルが変わり、このプロパティをbadgeVariants
関数に渡して、どのスタイルを適用するかを決定します。className
プロパティは、追加のスタイルを簡単に追加できるようにするものです。
Badge
コンポーネントの重要な部分の1つは、cnというユーティリティ関数です。この関数は、clsx
とtailwind-merge
という2つのライブラリを活用しています。
- clsx: 条件に応じてクラスを追加したり削除したりすることができます。例えば、"isActive"という条件がtrueの場合に特定の色のクラスを追加することができます。
- tailwind-merge: Tailwind CSSのスタイルが重複した場合に、正しいスタイルを維持するようにしてくれます。例えば、既存のスタイルが上書きされるときに、スタイルの衝突を防ぎます。
例えば、LinkというコンポーネントでisActive
がtrue
の場合、テキストの色を青に変更したいとします。clsx
だけを使用すると衝突が発生することがありますが、tailwind-merge
を組み合わせることで、問題なくスタイルが変更されます。
Discussion