Prodular UI

Data display

Chart

A themed wrapper for Recharts: series colors from the chart tokens, hairline grids, 12px muted axes, a popover tooltip, and built-in loading and empty states.

npx prodular-ui add chart

Area with gradient

One series, a soft gradient fill and the headline number in the card header.

Monthly recurring revenue
$48,290
+54.6% in 12 months

Stacked bar

Series without a color take chart-1 to chart-5 in order.

Active seats by plan
5,150 seats in October, up 34% since May

Two series

p95 and p50 latency with a reference line for the SLO.

API latency
Last 24 hours, all regions. SLO is 300 ms at p95.

Horizontal bars with labels

layout="vertical" for long category names, values printed at the end of each bar with LabelList.

Feature adoption
Weekly active users per feature

Bars and a line on two axes

ComposedChart with an amount on the left axis and a rate on the right.

Invoiced and collected
Bars on the left axis, the on-time rate on the right

Radial progress

RadialBarChart against a 0 to 100 domain for progress toward goals, with a plain legend beside it.

Q4 goals
Progress toward each target, 41 days left
  • New ARR82%
  • Expansion64%
  • Net retention91%

Loading and empty

loading draws skeleton bars, loading="line" an area silhouette, empty a message over the grid. The card keeps its height in every state.

Revenue, loading
Bars
Latency, loading
Line
Refunds, last 7 days
Empty

No data for this period

Pick a longer range or check back after the next sync.

Anatomy

const config = { mrr: { label: "MRR" } } satisfies ChartConfig
<ChartContainer config={config} className="aspect-auto h-64 w-full">  <AreaChart data={data}>    <CartesianGrid vertical={false} />    <XAxis dataKey="month" tickLine={false} axisLine={false} />    <ChartTooltip content={<ChartTooltipContent />} />    <Area dataKey="mrr" stroke="var(--color-mrr)" fill="var(--color-mrr)" />  </AreaChart></ChartContainer>

Guidance

Use it when

  • Trends over time: area for one cumulative metric, lines for comparing two or three series.
  • Composition over time: stacked bars for parts of a total, such as seats by plan.
  • Put every chart in a Card with the metric name and the current value in the header.
  • Horizontal bars when category names are long or there are more than six categories.
  • A combo chart only when the two measures explain each other, like amount and rate.

Avoid

  • More than five series. Group the rest into Other.
  • Pie charts for more than three parts. Use a stacked bar.
  • Raw colors in series. Use var(--chart-N) or leave color out of the config.
  • A spinner or blank card while data loads. Use loading so the layout does not jump.
  • Two axes for measures that share a unit. Put them on one axis.

Rules for AI agents

Published in llms-full.txt and the registry, so coding agents follow them when they build with this component.

  • Wrap every Recharts chart in ChartContainer with a config. Reference series colors as var(--color-<key>), never as hex or Tailwind palette colors.
  • Leave color out of the config to get the theme chart tokens in order, or set color: "var(--chart-2)" to pick one.
  • Give ChartContainer an explicit height: className="aspect-auto h-64 w-full".
  • Use <CartesianGrid vertical={false} /> and hide axis and tick lines (axisLine={false} tickLine={false}).
  • Format axis ticks short ($40k, 200 ms) with tickFormatter and tooltip values in full with valueFormatter on ChartTooltipContent.
  • Add ChartLegend with ChartLegendContent when there are two or more series.
  • Use a linearGradient from the series color at 0.28 opacity to 0 for area fills. Give each gradient a unique id.
  • While fetching, pass loading (bars) or loading="line" to ChartContainer and keep the chart children; they render once loading is false.
  • When the query returns no rows, pass empty, or a node with your own sentence, instead of rendering an empty chart.
  • For progress toward targets use RadialBarChart with PolarAngleAxis domain [0, 100] and background on RadialBar.

API

ChartContainer

PropTypeDefaultDescription
configChartConfigLabels, icons and colors per series key. Sets --color-<key> for each.
loadingboolean | "bars" | "line"falseShows a skeleton in the chart's place.
emptyboolean | ReactNodefalseShows the empty state. Pass a node for your own message.

ChartTooltipContent

PropTypeDefaultDescription
indicator"dot" | "line" | "dashed""dot"Series marker in the tooltip.
valueFormatter(value) => ReactNodeFormats each value, for example as currency.
hideLabelbooleanfalseHides the x value heading.

ChartLegendContent

PropTypeDefaultDescription
nameKeystringPayload key to look up labels in the config.