Price Chart
An area chart for displaying token price history with axes, grid lines, and tooltips
SOL Price
January 2026
import { PriceChart } from "@/components/sol/price-chart";
export function PriceChartDemo() {
return (
<PriceChart
title="SOL Price"
description="January 2026"
series={[
{ time: "2026-01-01", value: 148.32 },
{ time: "2026-01-02", value: 149.10 },
{ time: "2026-01-03", value: 147.85 },
{ time: "2026-01-04", value: 148.90 },
{ time: "2026-01-05", value: 150.20 },
{ time: "2026-01-06", value: 151.45 },
{ time: "2026-01-07", value: 150.80 },
{ time: "2026-01-08", value: 152.30 },
{ time: "2026-01-09", value: 151.60 },
{ time: "2026-01-10", value: 153.15 },
{ time: "2026-01-11", value: 152.40 },
{ time: "2026-01-12", value: 154.20 },
{ time: "2026-01-13", value: 153.80 },
{ time: "2026-01-14", value: 155.10 },
{ time: "2026-01-15", value: 154.60 },
{ time: "2026-01-16", value: 156.30 },
{ time: "2026-01-17", value: 155.80 },
{ time: "2026-01-18", value: 157.20 },
{ time: "2026-01-19", value: 156.50 },
{ time: "2026-01-20", value: 158.10 },
{ time: "2026-01-21", value: 157.40 },
{ time: "2026-01-22", value: 158.90 },
{ time: "2026-01-23", value: 159.30 },
{ time: "2026-01-24", value: 158.60 },
{ time: "2026-01-25", value: 160.10 },
{ time: "2026-01-26", value: 159.80 },
{ time: "2026-01-27", value: 161.20 },
{ time: "2026-01-28", value: 160.50 },
{ time: "2026-01-29", value: 161.80 },
{ time: "2026-01-30", value: 163.10 },
{ time: "2026-01-31", value: 162.56 },
]}
/>
);
}Installation
pnpm dlx shadcn@latest add @solanaui/price-chart
npx shadcn@latest add @solanaui/price-chart
yarn dlx shadcn@latest add @solanaui/price-chart
Usage
<PriceChart
title="SOL Price"
description="January 2026"
series={[
{ time: "2026-01-01", value: 148.32 },
{ time: "2026-01-15", value: 155.40 },
{ time: "2026-01-31", value: 162.56 },
]}
/>Without Title
<PriceChart
series={[
{ time: "2026-01-01", value: 148.32 },
{ time: "2026-01-15", value: 155.40 },
{ time: "2026-01-31", value: 162.56 },
]}
/>Source Code
"use client";import React from "react";import { Area, AreaChart, CartesianGrid, XAxis, YAxis } from "recharts";import { type ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent,} from "@/components/ui/chart";import { cn } from "@/lib/utils";interface PriceChartProps { title?: string; description?: string; series: { time: string; value: number; }[]; className?: string;}const POSITIVE_COLOR = "hsl(160 84% 39%)";const NEGATIVE_COLOR = "hsl(0 84% 67%)";const chartConfig = { value: { label: "Value", },} satisfies ChartConfig;const PriceChart = ({ title, description, series, className,}: PriceChartProps) => { const gradientId = React.useId(); if (!series.length) return null; const firstValue = series[0].value; const lastValue = series[series.length - 1].value; const isPositive = lastValue >= firstValue; const chartColor = isPositive ? POSITIVE_COLOR : NEGATIVE_COLOR; const minValue = Math.min(...series.map((s) => s.value)); const maxValue = Math.max(...series.map((s) => s.value)); const padding = (maxValue - minValue) * 0.1; return ( <div className={cn( "flex min-h-0 flex-1 flex-col gap-4 rounded-lg border bg-card p-4", className, )} > {(title || description) && ( <div className="flex flex-col gap-0.5"> {title && ( <h3 className="text-base font-semibold tracking-tight">{title}</h3> )} {description && ( <p className="text-sm text-muted-foreground">{description}</p> )} </div> )} <ChartContainer config={chartConfig} className="min-h-0 flex-1 w-full"> <AreaChart accessibilityLayer data={series}> <defs> <linearGradient id={gradientId} x1="0" y1="0" x2="0" y2="1"> <stop offset="0%" stopColor={chartColor} stopOpacity={0.2} /> <stop offset="100%" stopColor={chartColor} stopOpacity={0} /> </linearGradient> </defs> <CartesianGrid vertical={false} strokeDasharray="3 3" stroke="var(--border)" /> <XAxis dataKey="time" tickLine={false} axisLine={false} tickMargin={8} tickFormatter={(value: string) => { const date = new Date(value); return date.toLocaleDateString("en-US", { month: "short", day: "numeric", }); }} /> <YAxis domain={[minValue - padding, maxValue + padding]} tickLine={false} axisLine={false} tickMargin={8} tickFormatter={(value: number) => value >= 1 ? `$${value.toLocaleString(undefined, { maximumFractionDigits: 0 })}` : `$${value.toFixed(6)}` } width={60} /> <ChartTooltip content={ <ChartTooltipContent labelFormatter={(value: string) => { return new Date(value).toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric", }); }} formatter={(value) => { const num = Number(value); const formatted = num >= 1 ? `$${num.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}` : `$${num.toFixed(8)}`; return ( <span className="font-mono text-foreground"> {formatted} </span> ); }} /> } /> <Area dataKey="value" type="monotone" stroke={chartColor} strokeWidth={2} fill={`url(#${gradientId})`} dot={false} /> </AreaChart> </ChartContainer> </div> );};export type { PriceChartProps };export { PriceChart };