-

Token Trend Chart

PreviousNext

A dependency-light token usage chart for monitoring input tokens, output tokens, and cost.

Installation

pnpm
pnpm dlx shadcn@latest add https://ui.zgi.ai/r/token-trend-chart.json
npm
pnpm dlx shadcn@latest add https://ui.zgi.ai/r/token-trend-chart.json
yarn
yarn dlx shadcn@latest add https://ui.zgi.ai/r/token-trend-chart.json

Component

components/ui/token-trend-chart.tsx
"use client"

import * as React from "react"

import { cn } from "@/lib/utils"

export interface TokenTrendDatum {
  label: string
  inputTokens: number
  outputTokens: number
  cost?: number
}

export interface TokenTrendChartProps
  extends Omit<React.ComponentProps<"div">, "title"> {
  data: TokenTrendDatum[]
  title?: React.ReactNode
  description?: React.ReactNode
  height?: number
  showCost?: boolean
}

function formatCompact(value: number) {
  return Intl.NumberFormat("en", {
    notation: "compact",
    maximumFractionDigits: 1,
  }).format(value)
}

export function TokenTrendChart({
  data,
  title = "Token trend",
  description,
  height = 180,
  showCost = true,
  className,
  ...props
}: TokenTrendChartProps) {
  const maxTokens = Math.max(
    1,
    ...data.map((item) => item.inputTokens + item.outputTokens)
  )
  const totalInput = data.reduce((sum, item) => sum + item.inputTokens, 0)
  const totalOutput = data.reduce((sum, item) => sum + item.outputTokens, 0)
  const totalCost = data.reduce((sum, item) => sum + (item.cost ?? 0), 0)

  return (
    <div className={cn("w-full rounded-lg border p-4", className)} {...props}>
      <div className="flex flex-wrap items-start justify-between gap-3">
        <div>
          <h3 className="text-sm font-medium">{title}</h3>
          {description ? (
            <p className="text-muted-foreground mt-1 text-xs leading-5">
              {description}
            </p>
          ) : null}
        </div>
        <div className="flex flex-wrap gap-3 text-xs">
          <span className="flex items-center gap-1.5">
            <span className="size-2 rounded-sm bg-sky-500" />
            Input {formatCompact(totalInput)}
          </span>
          <span className="flex items-center gap-1.5">
            <span className="size-2 rounded-sm bg-emerald-500" />
            Output {formatCompact(totalOutput)}
          </span>
          {showCost ? (
            <span className="text-muted-foreground tabular-nums">
              ${totalCost.toFixed(2)}
            </span>
          ) : null}
        </div>
      </div>

      <div
        className="mt-5 flex items-end gap-2"
        style={{ height: `${height}px` }}
      >
        {data.map((item) => {
          const inputHeight = (item.inputTokens / maxTokens) * 100
          const outputHeight = (item.outputTokens / maxTokens) * 100
          const total = item.inputTokens + item.outputTokens

          return (
            <div
              key={item.label}
              className="flex min-w-0 flex-1 flex-col items-center gap-2"
            >
              <div className="flex h-full w-full items-end justify-center gap-1">
                <div
                  className="w-full max-w-5 rounded-t-sm bg-sky-500/85"
                  style={{ height: `${Math.max(3, inputHeight)}%` }}
                  title={`${item.label} input: ${item.inputTokens.toLocaleString()}`}
                />
                <div
                  className="w-full max-w-5 rounded-t-sm bg-emerald-500/85"
                  style={{ height: `${Math.max(3, outputHeight)}%` }}
                  title={`${item.label} output: ${item.outputTokens.toLocaleString()}`}
                />
              </div>
              <div className="w-full text-center">
                <div className="truncate text-xs font-medium">{item.label}</div>
                <div className="text-muted-foreground truncate text-[11px] tabular-nums">
                  {formatCompact(total)}
                </div>
              </div>
            </div>
          )
        })}
      </div>
    </div>
  )
}

Usage

import { TokenTrendChart } from "@/components/ui/token-trend-chart"
 
export function Example() {
  return (
    <TokenTrendChart
      data={[
        { label: "Mon", inputTokens: 148000, outputTokens: 42000, cost: 24.3 },
        { label: "Tue", inputTokens: 164000, outputTokens: 51000, cost: 28.1 },
      ]}
    />
  )
}

Props

PropTypeDefault
dataTokenTrendDatum[]required
titleReactNode"Token trend"
descriptionReactNode-
heightnumber180
showCostbooleantrue