shadcn/ui とは
shadcn/uiとは美しいデフォルトスタイルを備えたアクセシブルなUIコンポーネントのセットであり、独自のコンポーネントライブラリを構築するためのコード配布プラットフォームです。
従来のUIライブラリでは、パッケージをインストールしてコンポーネントを使い、必要に応じてスタイルを上書きしたりラップしたりしてカスタマイズしますが、この手法では独自デザインへの対応が難しくなります。
それに対してshadcnで提供されるコンポーネントはすべて手元で編集可能な「オープンコード」になっているのが特徴で、従来のUIライブラリでの課題を解決するものになっています。
shadcn chart とは
基本的な考え方は前述したオープンコードで提供されるコンポーネントであることは変わりません。チャート自体はRechartsを使うことが前提に作られており、shadcnではアプリケーションのテーマの統一、アクセシビリティの向上、デザインシステムとしての拡張性をもたらしてくれます。
プロジェクトの作成
Next.jsのアプリケーションをベースにshadcn chartを組み込むので、まずはNext.jsをインストールします。
pnpm create next-app@latest my-shadcn-charts --yes
次にshadcn chartsをインストールします。
pnpm dlx shadcn@latest add chart
rechartsのAreaChartをベースにshadcnのコンポーネントを追加したいので、適当に必要なデータを生成して表示させてみます。
"use client";
import { Area, AreaChart, CartesianGrid, XAxis, YAxis } from "recharts";
const chartData = [
{ month: "January", desktop: 186, mobile: 120, tablet: 90 },
{ month: "February", desktop: 305, mobile: 200, tablet: 150 },
{ month: "March", desktop: 237, mobile: 180, tablet: 130 },
{ month: "April", desktop: 73, mobile: 95, tablet: 60 },
{ month: "May", desktop: 209, mobile: 160, tablet: 120 },
{ month: "June", desktop: 214, mobile: 170, tablet: 140 },
{ month: "July", desktop: 250, mobile: 190, tablet: 160 },
{ month: "August", desktop: 280, mobile: 210, tablet: 180 },
{ month: "September", desktop: 230, mobile: 175, tablet: 135 },
{ month: "October", desktop: 190, mobile: 150, tablet: 120 },
{ month: "November", desktop: 220, mobile: 170, tablet: 140 },
{ month: "December", desktop: 260, mobile: 200, tablet: 160 },
];
export default function Charts() {
return (
<div className="flex justify-center items-center h-screen">
<AreaChart accessibilityLayer data={chartData} width={800} height={400}>
<CartesianGrid />
<XAxis
dataKey="month"
tickLine={false}
axisLine={false}
tickFormatter={(value) => value.slice(0, 3)}
/>
<YAxis tickLine={false} axisLine={false} tickMargin={8} tickCount={3} />
<Area dataKey="desktop" type="natural" fillOpacity={0.4} />
<Area dataKey="mobile" type="natural" fillOpacity={0.4} />
<Area dataKey="tablet" type="natural" fillOpacity={0.4} />
</AreaChart>
</div>
);
}
現状こんな感じです。
shadcn chartの利用
<AreaChart />を<ChartContainer />でラップすることにより、shadcnのスタイルが適応されます。Recharts自体をラップしたコンポーネントを使用しているわけではないので、チャート部分はRechartsのプリミティブな機能をそのまま備えています。
chartConfigでラベルやカラーを設定することができ、こうすることでダークテーマの対応が楽になり、アプリケーション全体のスタイルに一貫性が生まれます。CSS変数に関してはshadcn chartをインストールした時点でglobal.cssに定義されます。
import { ChartContainer, type ChartConfig } from "@/components/ui/chart";
...
// chartDateと対応させる
const chartConfig = {
desktop: {
label: "Desktop",
color: "var(--chart-1)",
},
tablet: {
label: "Tablet",
color: "var(--chart-2)",
},
mobile: {
label: "Mobile",
color: "var(--chart-3)",
},
} satisfies ChartConfig;
export default function Charts() {
return (
<div className="flex justify-center items-center h-screen">
<ChartContainer config={chartConfig} className="h-[400px] w-[800px]">
<AreaChart accessibilityLayer data={chartData} width={800} height={400}>
<CartesianGrid />
<XAxis
dataKey="month"
tickLine={false}
axisLine={false}
tickFormatter={(value) => value.slice(0, 3)}
/>
<YAxis
tickLine={false}
axisLine={false}
tickMargin={8}
tickCount={3}
/>
<Area
dataKey="desktop"
type="natural"
fill="var(--color-desktop)"
fillOpacity={0.4}
stroke="var(--color-desktop)"
/>
<Area
dataKey="mobile"
type="natural"
fill="var(--color-mobile)"
fillOpacity={0.4}
stroke="var(--color-mobile)"
/>
<Area
dataKey="tablet"
type="natural"
fill="var(--color-tablet)"
fillOpacity={0.4}
stroke="var(--color-tablet)"
/>
</AreaChart>
</ChartContainer>
</div>
);
}
ダークテーマ
色々追加してみる
shadcnでチャートをインストールするとカードコンポーネントも一緒にインストールされ、チャートをラップすることでより見栄えを整えることができます。
下記はツールチップの追加、カードとヘッダーとフッターの追加をした例です。
import {
ChartContainer,
type ChartConfig,
ChartTooltip,
ChartTooltipContent,
ChartLegend,
ChartLegendContent,
} from "@/components/ui/chart";
import {
Card,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from "@/components/ui/card";
...
export default function Charts() {
return (
<div className="flex justify-center items-center h-screen">
<Card>
<CardHeader>
<CardTitle className="text-lg font-semibold">Heading</CardTitle>
<CardDescription>description</CardDescription>
</CardHeader>
<CardContent>
<ChartContainer
config={chartConfig}
className="w-[600px] min-h-[200px]"
>
<AreaChart
accessibilityLayer
data={chartData}
margin={{
left: -20,
right: 12,
}}
>
<CartesianGrid />
<XAxis
dataKey="month"
tickLine={false}
axisLine={false}
tickFormatter={(value) => value.slice(0, 3)}
fontSize={14}
/>
<YAxis
tickLine={false}
axisLine={false}
tickMargin={8}
tickCount={3}
fontSize={14}
/>
<Area
dataKey="desktop"
type="natural"
fill="var(--color-desktop)"
fillOpacity={0.4}
stroke="var(--color-desktop)"
/>
<Area
dataKey="mobile"
type="natural"
fill="var(--color-mobile)"
fillOpacity={0.4}
stroke="var(--color-mobile)"
/>
<Area
dataKey="tablet"
type="natural"
fill="var(--color-tablet)"
fillOpacity={0.4}
stroke="var(--color-tablet)"
/>
<ChartTooltip content={<ChartTooltipContent />} />
<ChartLegend content={<ChartLegendContent />} />
</AreaChart>
</ChartContainer>
</CardContent>
<CardFooter>
<div className="flex w-full items-start gap-2 text-sm">
<div className="grid gap-2">
<div className="flex items-center gap-2 leading-none font-medium">
footer text
</div>
</div>
</div>
</CardFooter>
</Card>
</div>
);
}
一貫性のあるスタイルがあたり、見やすくなりました。
最後に
今回はチャートに焦点をあてましたが、ボタン、フォーム、タブ、テーブルなど、他にも多くのコンポーネントが提供されています。質の高いコンポーネントをスピード感をもって開発できるのと学習コストも低いので気軽に導入できる点もいいと思います。
ドキュメント



