Chart

Plots your data with tooltips, legends, and colors that track the theme.

import { Chart } from "@usefragments/ui";Source

Preview

<div style={{ width: '100%', height: 300 }}>
  <ChartContainer
    aria-label="Revenue and target by month"
    config={{
      revenue: { label: 'Revenue', series: 1 },
      target: { label: 'Target', series: 6 },

Usage

Use when

  • A trend over time is the point
  • Categories need comparing side by side
  • A whole splits into parts worth seeing

Avoid when

  • One number tells the story (use Text or Badge)
  • Distance to a goal (use Progress)
  • Readers need exact values (use Table)

Implementation notes

  • Wrap every recharts chart in ChartContainer
  • Map each data key to a label and a series index; draw the series with var(--fui-chart-N)
  • Never colour a series with a status hue — status colours mean status
  • Pair with ChartTooltip and ChartLegend rather than recharts' own
  • Give the container a real height — recharts cannot measure zero; loading, empty and error keep that height
  • A failed load passes error with words that say what to do and onRetry for the way out; an empty chart passes empty, emptyDescription and one emptyAction

Installation

pnpm add @usefragments/ui

The npm package stays managed by your package manager. Import styles once from @usefragments/ui/styles. See the installation guide for framework and theme setup.

Additional packages

  • recharts — Optional — powers Chart.Tooltip and Chart.Legend. Without it the container shows the data table, or a 'Chart unavailable' state.
pnpm add recharts

Anatomy

Import Chart once, then compose its parts with dot notation.

  • Chart.Tooltip
  • Chart.TooltipContent
  • Chart.Legend
  • Chart.LegendContent
  • Chart.preload

Examples

Bar Chart

Fixed categories, compared by height — the safest default.

<div style={{ width: '100%', height: 300 }}>
  <ChartContainer
    aria-label="Sessions by device"
    config={{ sessions: { label: 'Sessions', series: 1 } }}
  >
    <BarChart data={deviceData}>

Area Chart

The fill under the line stresses volume, not just direction.

<div style={{ width: '100%', height: 300 }}>
  <ChartContainer
    aria-label="Revenue by month"
    config={{ revenue: { label: 'Revenue', series: 3 } }}
  >
    <AreaChart data={monthlyData}>

States

Loading, empty and error stay in the chart's own box.

import { type ChartConfig } from "@usefragments/ui";

const config: ChartConfig = { revenue: { label: "Revenue", series: 1 } };
const data = [{ month: "Jan", revenue: 4200 }, { month: "Feb", revenue: 4800 }];

<>

API reference

Component props
Prop
Type
Default
Description
Chart.Legend.contentReact.ReactNode | ((legendProps: Record<string, unknown>) => React.ReactNode)Not set—
Chart.LegendContent.payloadreadonly (ChartPayloadEntry & { value?: string; })[] | undefinedNot set—
Chart.Tooltip.contentReact.ReactNode | ((tooltipProps: Record<string, unknown>) => React.ReactNode)Not set—
Chart.Tooltip.hideLabelboolean | undefinedNot set—
Chart.Tooltip.labelFormatter((label: string, payload: ChartTooltipContentProps["payload"]) => React.ReactNode) | undefinedNot set—
Chart.Tooltip.valueFormatter((value: number | string) => string) | undefinedNot set—
Chart.TooltipContent.activeboolean | undefinedNot set—
Chart.TooltipContent.hideLabelboolean | undefinedNot set—
Chart.TooltipContent.labelstring | undefinedNot set—
Chart.TooltipContent.labelFormatter((label: string, payload: ChartTooltipContentProps["payload"]) => React.ReactNode) | undefinedNot set—
Chart.TooltipContent.payloadreadonly ChartPayloadEntry[] | undefinedNot set—
Chart.TooltipContent.valueFormatter((value: number | string) => string) | undefinedNot set—
childrenRequiredReact.ReactElement<unknown, string | React.JSXElementConstructor<any>>Not setA recharts chart component (LineChart, BarChart, etc.)
configRequiredChartConfigNot setChartConfig mapping each data key to a label and a series index 1–6 (reads --fui-chart-N), with an optional legend icon
dataTableReact.ReactNodeNot setAccessible data table or textual fallback; shown visibly when recharts is missing
emptyReact.ReactNode"No data to show"The empty state's title, shown when the chart child's data is an empty array
emptyActionReact.ReactNodeNot setThe empty state's one way forward (a Button)
emptyDescriptionReact.ReactNodeNot setThe empty state's copy under the title: why there is nothing yet
errorReact.ReactNodeNot setWhen set, replaces the chart with an error box (danger glyph, this message, retry)
loadingboolean | undefinedfalseDraws a skeleton at the chart's height while the data loads
onRetry(() => void) | undefinedNot setRetry the failed load; shows a retry button in the error box
retryLabelstring | undefinedRetryLabel for the retry button
summarystring | undefinedNot setNon-visual summary announced to assistive technology users
styleCSSProperties | undefinedNot set—

Accessibility

  • The frame is role img with an aria-label; pass summary for the takeaway
  • ChartConfig labels are what the tooltip and legend read
  • Pass dataTable to offer the same numbers as text
  • Loading sets aria-busy; empty and error render as a labelled group with words, not colour; the error box is an alert
  • CardparentCharts are typically placed inside Cards
  • ProgressalternativeUse Progress for single-value completion
  • TablesiblingCombine with Table for full data views

Next steps