Components

Chart

Beautiful charts. Built using Recharts. Copy and paste into your apps.

PreviewSource
Bar Chart - Interactive
Showing total visitors for the last 3 months
Example requirements

Also uses: Card.

bun add --exact recharts@3.10.1

Installation

Complete the project setup first, including Tailwind CSS v4, theme tokens, and Preact compatibility aliases.

1. Install dependencies

bun add --exact cn@0.4.0 preact@11.0.0 recharts@3.10.1 tw-animate-css@1.4.0

The usage example also needs Card. Follow their installation guides as well.

2. Copy the component with degit

Run this from your project root. It selects chart.tsx, its local dependencies, and both licenses directly from the repository, then copies them into src/components/ui.

bunx degit@3.10.0 https://github.com/LiasCode/shadcn-preact#main ./.cache/shadcn-preact/chart --files LICENSE.md,registry/ui/chart.tsx,registry/ui/lib/utils.ts,registry/ui/primitives/LICENSE,registry/ui/primitives/internals/types.ts --force
mkdir -p ./src/components/ui
cp -R ./.cache/shadcn-preact/chart/registry/ui/. ./src/components/ui/
cp ./.cache/shadcn-preact/chart/LICENSE.md ./src/components/ui/LICENSE.md

The temporary copy lives in .cache/shadcn-preact/chart. Existing components stay in place; shared source files are updated from main.

Selected source files (4)

Usage

import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "./components/ui/card";
import {
  ChartContainer,
  ChartTooltip,
  ChartTooltipContent,
  type ChartConfig,
} from "./components/ui/chart";
import * as React from "preact/compat";
import { Bar, BarChart, CartesianGrid, XAxis } from "recharts";

export const description = "An interactive bar chart";

const chartData = [
  { date: "2024-04-01", desktop: 222, mobile: 150 },
  { date: "2024-04-02", desktop: 97, mobile: 180 },
  { date: "2024-04-03", desktop: 167, mobile: 120 },
  { date: "2024-04-04", desktop: 242, mobile: 260 },
  { date: "2024-04-05", desktop: 373, mobile: 290 },
  { date: "2024-04-06", desktop: 301, mobile: 340 },
  { date: "2024-04-07", desktop: 245, mobile: 180 },
  { date: "2024-04-08", desktop: 409, mobile: 320 },
  { date: "2024-04-09", desktop: 59, mobile: 110 },
  { date: "2024-04-10", desktop: 261, mobile: 190 },
  { date: "2024-04-11", desktop: 327, mobile: 350 },
  { date: "2024-04-12", desktop: 292, mobile: 210 },
  { date: "2024-04-13", desktop: 342, mobile: 380 },
  { date: "2024-04-14", desktop: 137, mobile: 220 },
  { date: "2024-04-15", desktop: 120, mobile: 170 },
  { date: "2024-04-16", desktop: 138, mobile: 190 },
  { date: "2024-04-17", desktop: 446, mobile: 360 },
  { date: "2024-04-18", desktop: 364, mobile: 410 },
  { date: "2024-04-19", desktop: 243, mobile: 180 },
  { date: "2024-04-20", desktop: 89, mobile: 150 },
  { date: "2024-04-21", desktop: 137, mobile: 200 },
  { date: "2024-04-22", desktop: 224, mobile: 170 },
  { date: "2024-04-23", desktop: 138, mobile: 230 },
  { date: "2024-04-24", desktop: 387, mobile: 290 },
  { date: "2024-04-25", desktop: 215, mobile: 250 },
  { date: "2024-04-26", desktop: 75, mobile: 130 },
  { date: "2024-04-27", desktop: 383, mobile: 420 },
  { date: "2024-04-28", desktop: 122, mobile: 180 },
  { date: "2024-04-29", desktop: 315, mobile: 240 },
  { date: "2024-04-30", desktop: 454, mobile: 380 },
];

const chartConfig = {
  views: {
    label: "Page Views",
  },
  desktop: {
    label: "Desktop",
    color: "var(--chart-2)",
  },
  mobile: {
    label: "Mobile",
    color: "var(--chart-1)",
  },
} satisfies ChartConfig;

export function ChartDemo() {
  const [activeChart, setActiveChart] = React.useState<keyof typeof chartConfig>("desktop");

  const total = React.useMemo(
    () => ({
      desktop: chartData.reduce((acc, curr) => acc + curr.desktop, 0),
      mobile: chartData.reduce((acc, curr) => acc + curr.mobile, 0),
    }),
    [],
  );

  return (
    <Card className="py-0 pb-4">
      <CardHeader className="flex flex-col items-stretch border-b p-0! sm:flex-row">
        <div className="flex flex-1 flex-col justify-center gap-1 px-6 pt-4 pb-3 sm:py-0!">
          <CardTitle>Bar Chart - Interactive</CardTitle>
          <CardDescription>Showing total visitors for the last 3 months</CardDescription>
        </div>
        <div className="flex">
          {["desktop", "mobile"].map((key) => {
            const chart = key as keyof typeof chartConfig;
            return (
              <button
                key={chart}
                data-active={activeChart === chart}
                className="relative z-30 flex flex-1 flex-col justify-center gap-1 border-t px-6 py-4 text-left even:border-l data-[active=true]:bg-muted/50 sm:border-t-0 sm:border-l sm:px-8 sm:py-6"
                onClick={() => setActiveChart(chart)}
              >
                <span className="text-xs text-muted-foreground">{chartConfig[chart].label}</span>
                <span className="text-lg leading-none font-bold sm:text-3xl">
                  {total[key as keyof typeof total].toLocaleString()}
                </span>
              </button>
            );
          })}
        </div>
      </CardHeader>
      <CardContent className="px-2 sm:p-6">
        <ChartContainer config={chartConfig} className="aspect-auto h-[250px] w-full">
          <BarChart
            accessibilityLayer
            data={chartData}
            margin={{
              left: 12,
              right: 12,
            }}
          >
            <CartesianGrid vertical={false} />
            <XAxis
              dataKey="date"
              tickLine={false}
              axisLine={false}
              tickMargin={8}
              minTickGap={32}
              tickFormatter={(value) => {
                const date = new Date(String(value));
                return date.toLocaleDateString("en-US", {
                  month: "short",
                  day: "numeric",
                });
              }}
            />
            <ChartTooltip
              content={
                <ChartTooltipContent
                  className="w-[150px]"
                  nameKey="views"
                  labelFormatter={(value) => {
                    return new Date(String(value)).toLocaleDateString("en-US", {
                      month: "short",
                      day: "numeric",
                      year: "numeric",
                    });
                  }}
                />
              }
            />
            <Bar dataKey={activeChart} fill={`var(--color-${activeChart})`} />
          </BarChart>
        </ChartContainer>
      </CardContent>
    </Card>
  );
}

Examples

Your First Chart

Let's build your first chart. We'll build a bar chart, add a grid, axis, tooltip and legend.

Your First ChartSource
Preview
Example requirements
bun add --exact recharts@3.10.1

Add a Grid

Let's add a grid to the chart.

Add a GridSource
Preview
Example requirements
bun add --exact recharts@3.10.1

Add an Axis

To add an x-axis to the chart, we'll use the XAxis component.

Add an AxisSource
Preview
Example requirements
bun add --exact recharts@3.10.1

Add Tooltip

So far we've only used components from Recharts. They look great out of the box thanks to some customization in the chart component.

Add TooltipSource
Preview
Example requirements
bun add --exact recharts@3.10.1

Add Legend

We'll do the same for the legend. We'll use the ChartLegend and ChartLegendContent components from chart.

Add LegendSource
Preview
Example requirements
bun add --exact recharts@3.10.1

Tooltip

A chart tooltip contains a label, name, indicator and value. You can use a combination of these to customize your tooltip.

TooltipSource
Preview
Example requirements
bun add --exact cn@0.4.0

Reference

See the official Chart documentation for composition patterns and API details. This page uses the Preact port and examples from the pinned upstream revision.

Component source