Chart
spell-ui/chartFreeComponent
Interactive line chart with a cursor-tracked tooltip card, snap-to-point hover, and built-in X-axis labels.
Live preview
live · rendered by the registry
Rendered by spell-ui on their own page — this is the component running, not a screenshot of it.Install it
npx shadcn@latest add https://spell.sh/r/chart.jsonSource
1"use client";23import * as React from "react";4import { cn } from "@/lib/utils";56const VIEWBOX_W = 640;7const VIEWBOX_H = 220;8const PAD_X = 0;9const PAD_Y_TOP = 24;10const PAD_Y_BOTTOM = 12;11const LINE_WIDTH = 2;12const CORNER_RADIUS = 2.5;13const TRANSITION = "200ms cubic-bezier(0.16, 1, 0.3, 1)";14const TOOLTIP_SHADOW = [15 "0 0 0 1px rgba(0, 0, 0, 0.04)",16 "0 1px 2px rgba(0, 0, 0, 0.04)",17 "0 4px 16px -4px rgba(0, 0, 0, 0.12)",18 "0 12px 32px -8px rgba(0, 0, 0, 0.08)",19].join(", ");20const DOT_SHADOW = "0 0 0 2px #FFF, 0 0 8px 2px rgba(0, 0, 0, 0.12)";2122function buildRoundedPath(23 pts: Array<{ x: number; y: number }>,24 radius: number,25): string {26 if (pts.length === 0) return "";27 const f = (n: number) => n.toFixed(3);28 if (pts.length === 1) return `M${f(pts[0].x)} ${f(pts[0].y)}`;2930 let d = `M${f(pts[0].x)} ${f(pts[0].y)}`;31 for (let i = 1; i < pts.length - 1; i++) {32 const prev = pts[i - 1];33 const curr = pts[i];34 const next = pts[i + 1];35 const inDx = curr.x - prev.x;36 const inDy = curr.y - prev.y;37 const inLen = Math.hypot(inDx, inDy) || 1;38 const outDx = next.x - curr.x;39 const outDy = next.y - curr.y;40 const outLen = Math.hypot(outDx, outDy) || 1;41 const r = Math.min(radius, inLen / 2, outLen / 2);42 const bx = curr.x - (inDx / inLen) * r;43 const by = curr.y - (inDy / inLen) * r;44 const ax = curr.x + (outDx / outLen) * r;45 const ay = curr.y + (outDy / outLen) * r;46 d += ` L${f(bx)} ${f(by)} Q${f(curr.x)} ${f(curr.y)} ${f(ax)} ${f(ay)}`;47 }48 const last = pts[pts.length - 1];49 d += ` L${f(last.x)} ${f(last.y)}`;50 return d;51}5253export interface ChartProps {54 /** Numeric values to plot — one segment per pair of consecutive points. */55 data: number[];56 /** Optional label for each data point — shown at the top of the tooltip card. */57 labels?: string[];58 /** Series name shown next to the indicator dot in the tooltip. */59 name?: string;60 /** Line + dot color as a hex string (e.g. `"#0090FD"`). Default `"#0090FD"`. */61 color?: string;62 /** Maximum chart width in px. The chart preserves a 640:220 aspect ratio. Default `640`. */63 width?: number;64 /** Format the tooltip value. Receives the value and its index. */65 formatValue?: (value: number, index: number) => React.ReactNode;66 /** Index of the active point on initial render. Defaults to the last point. */67 defaultIndex?: number;68 /** Show X-axis tick labels at the bottom. Requires `labels`. Default `true`. */69 showXAxis?: boolean;70// … truncated
Files it writes
More from spell-ui
All 33 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Animated Checkboxanimated-checkbox | spell-ui | Components | Free | 1 dep | |
| Animated Gradientanimated-gradient | spell-ui | Components | Free | no deps | |
| Badgebadge | spell-ui | Components | Free | 2 deps | |
| Bars Spinnerbars-spinner | spell-ui | Components | Free | no deps | |
| Blur Revealblur-reveal | spell-ui | Components | Free | 1 dep | |
| Color Selectorcolor-selector | spell-ui | Components | Free | no deps | |
| Copy Buttoncopy-button | spell-ui | Components | Free | 1 dep | |
| Exploding Inputexploding-input | spell-ui | Components | Free | no deps |
