Data display
Sparkline
Word-sized trend line that inherits colour and never mirrors.
Volume+24%
pnpm dlx shadcn@latest add @paragon/sparklineBrings incn
registry/paragon/components/sparkline.tsx
import * as React from "react"
import { cn } from "cn"
/**
* A word-sized trend line. Stretches to its box, keeps a hairline stroke at any
* size, and inherits colour from the text. Time runs left to right in every
* language, so it never mirrors.
*/
function Sparkline({
values,
area = false,
className,
...props
}: Omit<React.ComponentProps<"svg">, "values"> & {
values: number[]
/** Fill beneath the line with a soft fade of the same colour. */
area?: boolean
}) {
const id = React.useId()
if (values.length < 2) return null
const min = Math.min(...values)
const max = Math.max(...values)
const range = max - min || 1
const points = values.map((value, index) => [
(index / (values.length - 1)) * 100,
30 - ((value - min) / range) * 28,
])
const line = points.map(([x, y], index) => `${index ? "L" : "M"}${x.toFixed(2)} ${y.toFixed(2)}`).join(" ")
return (
<svg
viewBox="0 0 100 32"
preserveAspectRatio="none"
aria-hidden="true"
data-slot="sparkline"
className={cn("h-8 w-24 overflow-visible text-foreground/70", className)}
{...props}
>
{area ? (
<>
<defs>
<linearGradient id={`${id}-fill`} x1="0" x2="0" y1="0" y2="1">
<stop offset="0%" stopColor="currentColor" stopOpacity="0.18" />
<stop offset="100%" stopColor="currentColor" stopOpacity="0" />
</linearGradient>
</defs>
<path d={`${line} L100 32 L0 32 Z`} fill={`url(#${id}-fill)`} />
</>
) : null}
<path
d={line}
fill="none"
stroke="currentColor"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
vectorEffect="non-scaling-stroke"
/>
</svg>
)
}
export { Sparkline }