shadcn/uiに新たなコンポーネントにChartが追加されました。ChartコンポーネントはRechartライブラリを利用してUIコンポーネントは作成されており、React上で簡単にチャート/グラフを描写することができます。

shadcn/uiはTailwind CSSを元に作成されているライブラリで現在人気急上昇中のライブラリの一つです。Tailwind CSSを利用したことはあるけどまだshadcn/uiを使ったことがない人には下記の記事が参考になります。

プロジェクトの作成

Next.jsを利用してshadcn/uiのChartの動作確認を行うので”npx create-next-app@latest”コマンドでプロジェクトの作成を行います。コマンドを実行するといくつか質問がありますがすべてデフォルトを選択しています。任意の名前をつけれるプロジェクト名には”shadcn-chart”としています。


% npx create-next-app@latest
Need to install the following packages:
create-next-app@14.2.5
Ok to proceed? (y) y

✔ What is your project named? … shadcn-chart
✔ Would you like to use TypeScript? … No / Yes
✔ Would you like to use ESLint? … No / Yes
✔ Would you like to use Tailwind CSS? … No / Yes
✔ Would you like to use `src/` directory? … No / Yes
✔ Would you like to use App Router? (recommended) … No / Yes
✔ Would you like to customize the default import alias (@/*)? … No / Yes
Creating a new Next.js app in /Users/mac/Desktop/shadcn-chart.

//略

shadcn/uiの設定

プロジェクトを作成後、shadcn/uiの初期設定を行うため以下のコマンドを実行します。


% npx shadcn-ui@latest init

✔ Which style would you like to use? › Default
✔ Which color would you like to use as base color? › Slate
✔ Would you like to use CSS variables for colors? … no / yes

✔ Writing components.json...
✔ Initializing project...
✔ Installing dependencies...

Success! Project initialization completed. You may now add components.

次にchartコンポーネントのインストールを行います。


 % npx shadcn-ui@latest add chart

インストールが完了するとcomponents/uiディレクトリの下にcard.tsx, chart.tsxの2つのファイルが作成されます。global.cssファイルにはchartのカラーが追加されていることを確認することができます。


@tailwind base;
@tailwind components;
@tailwind utilities;

@layer base {
  :root {
//略
    --chart-1: 12 76% 61%;
    --chart-2: 173 58% 39%;
    --chart-3: 197 37% 24%;
    --chart-4: 43 74% 66%;
    --chart-5: 27 87% 67%;
  }

  .dark {
//略
    --chart-1: 220 70% 50%;
    --chart-2: 160 60% 45%;
    --chart-3: 30 80% 55%;
    --chart-4: 280 65% 60%;
    --chart-5: 340 75% 55%;
  }
}

はじめてのChart

ドキュメントに記載されているコードを利用してChartをブラウザ上に描写します。componentsディレクトリにexample-chart.tsxファイルを作成します。rechartからimportしたBarChart, BarコンポーネントをChartContainerでwrapしています。


'use client';

import { Bar, BarChart } from 'recharts';

import { ChartConfig, ChartContainer } from '@/components/ui/chart';

const chartData = [
  { month: 'January', desktop: 186, mobile: 80 },
  { month: 'February', desktop: 305, mobile: 200 },
  { month: 'March', desktop: 237, mobile: 120 },
  { month: 'April', desktop: 73, mobile: 190 },
  { month: 'May', desktop: 209, mobile: 130 },
  { month: 'June', desktop: 214, mobile: 140 },
];

const chartConfig = {
  desktop: {
    label: 'Desktop',
    color: 'hsl(var(--chart-1))',
  },
  mobile: {
    label: 'Mobile',
    color: 'hsl(var(--chart-2))',
  },
} satisfies ChartConfig;

export function Component() {
  return (
    <ChartContainer config={chartConfig} className="min-h-[200px] w-full">
      <BarChart accessibilityLayer data={chartData}>
        <Bar dataKey="desktop" fill="var(--color-desktop)" radius={4} />
        <Bar dataKey="mobile" fill="var(--color-mobile)" radius={4} />
      </BarChart>
    </ChartContainer>
  );
}

page.tsxファイルで作成したexample-chart.tsxファイルのComponentをimportします。


import { Component } from '../components/example-chart';

export default function Home() {
  return (
    <main className="flex min-h-screen flex-col items-center justify-between p-24">
      <Component />
    </main>
  );
}

“npm run dev”コマンドを実行して開発サーバを起動します。

ブラウザで確認するとBar Chartが表示されます。

BarChartの表示
BarChartの表示

ダークモードでの表示

shadcn/uiではダークモードの切り替え機能の実装をコンポーネントをインストールすることが簡単に実装することができます。

最初にnext-themesライブラリのインストールを行います。


 % npm install next-themes

インストール完了後にcomponentsディレクトリの下にtheme-provider.tsxファイルを作成します。


'use client';

import * as React from 'react';
import { ThemeProvider as NextThemesProvider } from 'next-themes';
import { type ThemeProviderProps } from 'next-themes/dist/types';

export function ThemeProvider({ children, ...props }: ThemeProviderProps) {
  return <NextThemesProvider {...props}>{children}</NextThemesProvider>;
}

作成したtheme-providerでlayout.tsxファイルのchildrenをwrapします。


import type { Metadata } from 'next';
import { Inter } from 'next/font/google';
import './globals.css';
import { ThemeProvider } from '@/components/theme-provider';

const inter = Inter({ subsets: ['latin'] });

export const metadata: Metadata = {
  title: 'Create Next App',
  description: 'Generated by create next app',
};

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <html lang="en">
      <body className={inter.className}>
        <ThemeProvider
          attribute="class"
          defaultTheme="system"
          enableSystem
          disableTransitionOnChange
        >
          {children}
        </ThemeProvider>
      </body>
    </html>
  );
}

DarkモードとLightモードを切り替えるコンポーネントを作成するためcomponetsディレクトリにthem-change.tsxファイルを作成します。


'use client';

import * as React from 'react';
import { Moon, Sun } from 'lucide-react';
import { useTheme } from 'next-themes';

import { Button } from '@/components/ui/button';
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu';

export function ModeToggle() {
  const { setTheme } = useTheme();

  return (
    <DropdownMenu>
      <DropdownMenuTrigger asChild>
        <Button variant="outline" size="icon">
          <Sun className="h-[1.2rem] w-[1.2rem] rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" />
          <Moon className="absolute h-[1.2rem] w-[1.2rem] rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" />
          <span className="sr-only">Toggle theme</span>
        </Button>
      </DropdownMenuTrigger>
      <DropdownMenuContent align="end">
        <DropdownMenuItem onClick={() => setTheme('light')}>
          Light
        </DropdownMenuItem>
        <DropdownMenuItem onClick={() => setTheme('dark')}>
          Dark
        </DropdownMenuItem>
        <DropdownMenuItem onClick={() => setTheme('system')}>
          System
        </DropdownMenuItem>
      </DropdownMenuContent>
    </DropdownMenu>
  );
}

theme-change.tsxファイルのModeToggleコンポーネントではDropdown-menu, buttonコンポーネントを利用しているので2つのコンポーネントのインストールを行います。


 % npx shadcn-ui@latest add dropdown-menu
 % npx shadcn-ui@latest add button

page.tsxファイルでModeToggleコンポーネントをimportします。


import { ModeToggle } from '@/components/theme-change';
import { Component } from '../components/example-chart';

export default function Home() {
  return (
    <main className="flex min-h-screen flex-col items-center justify-between p-24">
      <ModeToggle />
      <Component />
    </main>
  );
}

モードの切り替えの設定は完了したのでブラウザ上でDarkコードとLightモードの切り替えが行えるようになります。切り替えは画面上部に表示されているアイコンを利用して行うことができます。Darkコードに切り替えると下記のように表示されます。

DarkモードでのBar Chartの表示
DarkモードでのBar Chartの表示

Cardコンポーネント

Chartコンポーネントをインストールするとchart.tsxファイルと一緒にcartd.tsxファイルもインストールされていました。Chartコンポーネントの中でcard.tsxファイルをどのように利用するのか確認します。

CardコンポーネントはChartContainerをWrapすることでCardの中にChartの説明とChartを一緒に含まることができます。Header, FooterやTitle, Descriptionのコンポーネントも利用できます。


'use client';

import { Bar, BarChart } from 'recharts';

import { ChartConfig, ChartContainer } from '@/components/ui/chart';
import {
  Card,
  CardContent,
  CardDescription,
  CardFooter,
  CardHeader,
  CardTitle,
} from '@/components/ui/card';

const chartData = [
  { month: 'January', desktop: 186, mobile: 80 },
  { month: 'February', desktop: 305, mobile: 200 },
  { month: 'March', desktop: 237, mobile: 120 },
  { month: 'April', desktop: 73, mobile: 190 },
  { month: 'May', desktop: 209, mobile: 130 },
  { month: 'June', desktop: 214, mobile: 140 },
];

const chartConfig = {
  desktop: {
    label: 'Desktop',
    color: 'hsl(var(--chart-1))',
  },
  mobile: {
    label: 'Mobile',
    color: 'hsl(var(--chart-2))',
  },
} satisfies ChartConfig;

export function Component() {
  return (
    <Card>
      <CardHeader>
        <CardTitle>Bar Chart - Multiple</CardTitle>
        <CardDescription>January - June 2024</CardDescription>
      </CardHeader>
      <CardContent>
        <ChartContainer config={chartConfig} className="min-h-[200px] w-full">
          <BarChart accessibilityLayer data={chartData}>
            <Bar dataKey="desktop" fill="var(--color-desktop)" radius={4} />
            <Bar dataKey="mobile" fill="var(--color-mobile)" radius={4} />
          </BarChart>
        </ChartContainer>
        <CardFooter className="flex-col items-start gap-2 text-sm">
          <div className="flex gap-2 font-medium leading-none">
            Trending up by 5.2% this month
          </div>
          <div className="leading-none text-muted-foreground">
            Showing total visitors for the last 6 months
          </div>
        </CardFooter>
      </CardContent>
    </Card>
  );
}

Cardコンポーネントを利用するだけでぐっとデザインがよくなることがわかります。

Cardコンポーネントを利用した場合
Cardコンポーネントを利用した場合

ダークモードだとこのように表示されます。

shadcnでCardも含めた場合のダークモード
shadcnでCardも含めた場合のダークモード

shadcn/uiを利用することでChartの表示、ダークモードの切り替えも簡単に実装できるようになります。